Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Hopcroft Karp & CHT #20

Merged
merged 12 commits into from
Oct 8, 2020
71 changes: 71 additions & 0 deletions convexhull_trick.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
struct convexhull_trick
{
//일단 binary search와 linear둘다 구현해둠
struct line
{
long long a, b;
pair<long long, long long> start_x;// first/second
long long y(long long x){return a*x + b;}
static bool compare_x(line& l, const line& l1, const line& l2)//intersect_x(l, l1) < intersect_x(l, l2)
{
long long t1 = (l1.b - l.b) * (l.a - l2.a);
long long t2 = (l2.b - l.b) * (l.a - l1.a);
bool op = (l.a - l2.a < 0) ^ (l.a - l1.a < 0);
return op? t1>t2:t1<t2;
}
bool not_start(long long x)//start_x > x
{
if (start_x.second < 0) return start_x.first < x*start_x.second;
return start_x.first > x * start_x.second;
}
};
vector<line> stk;
int qptr;
convexhull_trick(int capacity = 100'010) : qptr(0)
{
stk.reserve(capacity);
}
void init(int capacity = 100'010)
{
stk.clear();
stk.reserve(capacity);
qptr = 0;
}
void push_line(line l)
{
while(stk.size() > 1)
{
line& l1 = stk[stk.size() - 1];
line& l2 = stk[stk.size() - 2];
if (line::compare_x(l, l2, l1)) break;
stk.pop_back();
}
if (qptr >= stk.size()) qptr = stk.size() - 1;
if(!stk.empty()) l.start_x = make_pair(stk.back().b - l.b, l.a - stk.back().a);
else l.start_x = make_pair(0LL, 0LL);
stk.push_back(l);
}
void push_line(long long a, long long b)
{
push_line({a, b});
}
long long query_bs(long long x)
{
int lf = 0, rg = stk.size() - 1;
while(lf < rg)
{
int mid = (lf + rg + 1) / 2;
if (stk[mid].not_start(x))
{
rg = mid - 1;
}else lf = mid;
}
return stk[lf].y(x);
}
long long query_linear(long long x)//x값이 증가하는 순서대로 들어와야함
{
while(qptr + 1 < stk.size() && !stk[qptr+1].not_start(x))
++qptr;
return stk[qptr].y(x);
}
};
60 changes: 60 additions & 0 deletions hopcroft_karp.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
struct hopcroft_karp{
//0based-index
int nx, ny;
vector<int> X;//X[x] = 집합 X의 원소 x가 어떤 y에 대응되어 있는가?
vector<int> Y;//Y[y] = 집합 Y의 원소 y가 어떤 x에 대응되어 있는가?
vector<vector<int>> adj; // X -> Y 형태의 이분그래프, X를 Y로 대응한다.
vector<int> dist;
hopcroft_karp(int nx, int ny) : nx(nx), ny(ny){ //집합 X와 Y의 크기
X.resize(nx);
Y.resize(ny);
adj.resize(nx);
dist.resize(nx);
}
void add_edge(int x, int y){
adj[x].push_back(y);
}

void assign_level(){
queue<int> q;
for(int i=0;i<nx;++i){
if (X[i] == -1){
dist[i] = 0;
q.push(i);
} else dist[i] = -1;
}
while(!q.empty()){
int now = q.front(); q.pop();
for (int nxt: adj[now]){
if (Y[nxt] != -1 && dist[Y[nxt]] == -1){
dist[Y[nxt]] = dist[now] + 1;
q.push(Y[nxt]);
}
}
}
}
bool find_match(int now){
for (int nxt: adj[now]){
if (Y[nxt] == -1 || dist[Y[nxt]] == dist[now] + 1 && find_match(Y[nxt])){
Y[nxt] = now;
X[now] = nxt;
return true;
}
}
return false;
}
int operator()(){
X.assign(nx, -1);
Y.assign(ny, -1);
int ret = 0;
int flow = 0;
do{
assign_level();
flow = 0;
for(int i=0;i<nx;++i)
flow += X[i] == -1 && find_match(i);
ret += flow;
}while(flow);
return ret;
}
};