teamnote default
This commit is contained in:
5
source/Graph/2SAT.cpp
Normal file
5
source/Graph/2SAT.cpp
Normal file
@@ -0,0 +1,5 @@
|
||||
ok = true; // 1<=i&&i<=n : $x$, n+1<=i&&i<=2*n : $!x$
|
||||
forr(i, n) {
|
||||
if (scn[i] == scn[i+n]) ok = false;
|
||||
ans[i] = (scn[i] < scn[i+n]);
|
||||
}
|
||||
13
source/Graph/BipartiteMatching.cpp
Normal file
13
source/Graph/BipartiteMatching.cpp
Normal file
@@ -0,0 +1,13 @@
|
||||
vector<int> sideadj[N];
|
||||
int selby[M];
|
||||
int chk[M], c;
|
||||
bool matching(int s) {
|
||||
for(auto i : sideadj[s]) {
|
||||
if(chk[i] == c) continue;
|
||||
chk[i] = c;
|
||||
if(selby[i] and !matching(selby[i])) continue;
|
||||
selby[i] = s;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
69
source/Graph/Dinic.cpp
Normal file
69
source/Graph/Dinic.cpp
Normal file
@@ -0,0 +1,69 @@
|
||||
struct Edge {
|
||||
int to, cap, now;
|
||||
Edge* rev;
|
||||
Edge(int to,int cap):to(to), cap(cap), now(0){}
|
||||
int left(){return cap - now;}
|
||||
void flow(int f){now += f; rev->now -= f;}
|
||||
void reset(){now = 0;}
|
||||
};
|
||||
vector<Edge*> adj[N];
|
||||
|
||||
int lv[N]; bool chk[N];
|
||||
bool bfs(int S, int T) {
|
||||
queue<int> q;
|
||||
q.push(S); lv[S] = 0; chk[S] = true;
|
||||
while(!q.empty()) {
|
||||
int s = q.front(); q.pop();
|
||||
for(auto i : adj[s]) {
|
||||
if(i->left() and !chk[i->to]) {
|
||||
lv[i->to] = lv[s]+1; chk[i->to] = true;
|
||||
q.push(i->to);
|
||||
}
|
||||
}
|
||||
}
|
||||
return chk[T];
|
||||
}
|
||||
|
||||
Edge* hist[N]; int last[N];
|
||||
bool dfs(int s, int T) {
|
||||
if(s == T) return true;
|
||||
|
||||
for(int &j=last[s]; j < adj[s].size(); j++) {
|
||||
int i = adj[s][j]->to;
|
||||
if(adj[s][j]->left() == 0 or lv[i] != lv[s]+1) continue;
|
||||
hist[i] = adj[s][j];
|
||||
|
||||
if(dfs(i, T)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
ll flow(int S,int T) {
|
||||
ll ans = 0;
|
||||
while(bfs(S, T)) {
|
||||
while(dfs(S, T)) {
|
||||
int m = 2e9;
|
||||
int now = T;
|
||||
while(S != now) {
|
||||
m = min(m, hist[now]->left());
|
||||
now = hist[now]->rev->to;
|
||||
}
|
||||
now = T;
|
||||
while(S != now)
|
||||
hist[now]->flow(m), now = hist[now]->rev->to;
|
||||
ans += m;
|
||||
}
|
||||
memset(last, 0, sizeof last);
|
||||
memset(chk, 0, sizeof chk);
|
||||
}
|
||||
return ans;
|
||||
}
|
||||
// isDir : isDirected => 양방향 간선이면 false
|
||||
void connect(int from, int to, int cap, bool isDir = true) {
|
||||
Edge *fw, *bw;
|
||||
fw = new Edge(to, cap);
|
||||
bw = new Edge(from, !isDir ? cap : 0);
|
||||
fw->rev = bw; bw->rev = fw;
|
||||
adj[from].push_back(fw);
|
||||
adj[to].push_back(bw);
|
||||
}
|
||||
51
source/Graph/DominatorTree.cpp
Normal file
51
source/Graph/DominatorTree.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
// https://ideone.com/aO6cH4
|
||||
namespace dtree{ // by cki86201
|
||||
vector<int> E[N], RE[N], rdom[N];
|
||||
int S[N], RS[N], cs;
|
||||
int par[N], val[N], sdom[N], rp[N], dom[N];
|
||||
void clear(int n) { cs = 0;
|
||||
for(int i=0;i<=n;i++) {
|
||||
par[i] = val[i] = sdom[i] = rp[i] = dom[i] = S[i] = RS[i] = 0;
|
||||
E[i].clear(); RE[i].clear(); rdom[i].clear();
|
||||
}
|
||||
}
|
||||
void add_edge(int x, int y) { E[x].push_back(y); }
|
||||
void Union(int x, int y) { par[x] = y; }
|
||||
int Find(int x, int c = 0) {
|
||||
if(par[x] == x) return c ? -1 : x;
|
||||
int p = Find(par[x], 1);
|
||||
if(p == -1) return c ? par[x] : val[x];
|
||||
if(sdom[val[x]] > sdom[val[par[x]]]) val[x] = val[par[x]];
|
||||
par[x] = p;
|
||||
return c ? p : val[x];
|
||||
}
|
||||
void dfs(int x) {
|
||||
RS[ S[x] = ++cs ] = x;
|
||||
par[cs] = sdom[cs] = val[cs] = cs;
|
||||
for(int e : E[x]) {
|
||||
if(S[e] == 0) dfs(e), rp[S[e]] = S[x];
|
||||
RE[S[e]].push_back(S[x]);
|
||||
}
|
||||
}
|
||||
int solve(int s, int *up) { // Calculate idoms
|
||||
dfs(s);
|
||||
for(int i=cs;i;i--) {
|
||||
for(int e : RE[i]) sdom[i] = min(sdom[i], sdom[Find(e)]);
|
||||
if(i > 1) rdom[sdom[i]].push_back(i);
|
||||
for(int e : rdom[i]) {
|
||||
int p = Find(e);
|
||||
if(sdom[p] == i) dom[e] = i;
|
||||
else dom[e] = p;
|
||||
}
|
||||
if(i > 1) Union(i, rp[i]);
|
||||
}
|
||||
for(int i=2;i<=cs;i++) if(sdom[i] != dom[i]) dom[i] = dom[dom[i]];
|
||||
for(int i=2;i<=cs;i++) up[RS[i]] = RS[dom[i]];
|
||||
return cs;
|
||||
}
|
||||
} // namespace dtree
|
||||
|
||||
int par[N];
|
||||
dtree::add_edge(a, b); // a -> b
|
||||
int cnt = dtree::solve(s, par);
|
||||
// cnt : s에서 도달할 수 있는 정점, par: dominator tree의 par
|
||||
67
source/Graph/MCMF.cpp
Normal file
67
source/Graph/MCMF.cpp
Normal file
@@ -0,0 +1,67 @@
|
||||
struct Edge {
|
||||
int to, cap, now;
|
||||
ll cost;
|
||||
Edge* rev;
|
||||
Edge(int to,int cap, ll cost)
|
||||
:to(to), cap(cap), now(0), cost(cost){}
|
||||
int left(){return cap - now;}
|
||||
ll flow(int f)
|
||||
{now += f; rev->now -= f; return cost * f;}
|
||||
void reset(){now = 0;}
|
||||
};
|
||||
vector<Edge*> adj[N];
|
||||
Edge* hist[N]; ll dist[N]; bool inQueue[N], chk[N];
|
||||
bool spfa(int s, int t) {
|
||||
memset(dist, 0, sizeof(dist));
|
||||
memset(chk, 0, sizeof(chk)); chk[s] = true;
|
||||
queue<int> q;
|
||||
memset(inQueue, 0, sizeof(inQueue));
|
||||
q.push(s); inQueue[s] = true;
|
||||
while(!q.empty()) {
|
||||
int now = q.front();
|
||||
q.pop(); inQueue[now] = false;
|
||||
|
||||
for(auto e : adj[now]) {
|
||||
int next = e->to;
|
||||
if(e->left() > 0 and
|
||||
(chk[next] == false
|
||||
or dist[next] > dist[now] + e->cost)) {
|
||||
chk[next] = true;
|
||||
dist[next] = dist[now] + e->cost;
|
||||
hist[next] = e;
|
||||
if(!inQueue[next])
|
||||
q.push(next), inQueue[next] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return chk[t];
|
||||
}
|
||||
// cost가 들어가면 항상 단방향만 가능하다. (양방향 : 2번 connect)
|
||||
void connect(int from, int to, int cap, ll cost) {
|
||||
Edge *fw, *bw;
|
||||
fw = new Edge(to, cap, cost);
|
||||
bw = new Edge(from, 0, -cost);
|
||||
fw->rev = bw; bw->rev = fw;
|
||||
adj[from].push_back(fw);
|
||||
adj[to].push_back(bw);
|
||||
}
|
||||
//maximum matching & minimum cost
|
||||
pair<ll, ll> flow(int S,int T) {
|
||||
ll ans = 0; ll cost = 0;
|
||||
while(spfa(S, T)) {
|
||||
int m = 2e9;
|
||||
|
||||
int now = T;
|
||||
while(S != now) {
|
||||
m = min(m, hist[now]->left());
|
||||
now = hist[now]->rev->to;
|
||||
}
|
||||
now = T;
|
||||
while(S != now) {
|
||||
cost += hist[now]->flow(m);
|
||||
now = hist[now]->rev->to;
|
||||
}
|
||||
ans += m;
|
||||
}
|
||||
return {ans, cost};
|
||||
}
|
||||
74
source/Graph/Matching.cpp
Normal file
74
source/Graph/Matching.cpp
Normal file
@@ -0,0 +1,74 @@
|
||||
// From https://github.com/koosaga/olympiad
|
||||
// matching_short.cpp
|
||||
const int MAXN = 2020 + 1;
|
||||
// 1-based Vertex index
|
||||
int vis[MAXN], par[MAXN], orig[MAXN], match[MAXN], aux[MAXN], t, N;
|
||||
vector<int> conn[MAXN];
|
||||
queue<int> Q;
|
||||
void addEdge(int u, int v) { conn[u].push_back(v); conn[v].push_back(u); }
|
||||
void init(int n) {
|
||||
N = n; t = 0;
|
||||
for(int i=0; i<=n; ++i) {
|
||||
conn[i].clear();
|
||||
match[i] = aux[i] = par[i] = 0;
|
||||
}
|
||||
}
|
||||
void augment(int u, int v) {
|
||||
int pv = v, nv;
|
||||
do {
|
||||
pv = par[v]; nv = match[pv];
|
||||
match[v] = pv; match[pv] = v;
|
||||
v = nv;
|
||||
} while(u != pv);
|
||||
}
|
||||
int lca(int v, int w) {
|
||||
++t;
|
||||
while(true) {
|
||||
if(v) {
|
||||
if(aux[v] == t) return v; aux[v] = t;
|
||||
v = orig[par[match[v]]];
|
||||
}
|
||||
swap(v, w);
|
||||
}
|
||||
}
|
||||
void blossom(int v, int w, int a) {
|
||||
while(orig[v] != a) {
|
||||
par[v] = w; w = match[v];
|
||||
if(vis[w] == 1) Q.push(w), vis[w] = 0;
|
||||
orig[v] = orig[w] = a;
|
||||
v = par[w];
|
||||
}
|
||||
}
|
||||
bool bfs(int u) {
|
||||
fill(vis+1, vis+1+N, -1); iota(orig + 1, orig + N + 1, 1);
|
||||
Q = queue<int> (); Q.push(u); vis[u] = 0;
|
||||
while(!Q.empty()) {
|
||||
int v = Q.front(); Q.pop();
|
||||
for(int x: conn[v]) {
|
||||
if(vis[x] == -1) {
|
||||
par[x] = v; vis[x] = 1;
|
||||
if(!match[x]) return augment(u, x), true;
|
||||
Q.push(match[x]); vis[match[x]] = 0;
|
||||
}
|
||||
else if(vis[x] == 0 && orig[v] != orig[x]) {
|
||||
int a = lca(orig[v], orig[x]);
|
||||
blossom(x, v, a); blossom(v, x, a);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
int Match() {
|
||||
int ans = 0;
|
||||
// find random matching (not necessary, constant improvement)
|
||||
vector<int> V(N-1); iota(V.begin(), V.end(), 1);
|
||||
shuffle(V.begin(), V.end(), mt19937(0x94949));
|
||||
for(auto x: V) if(!match[x]){
|
||||
for(auto y: conn[x]) if(!match[y]) {
|
||||
match[x] = y, match[y] = x;
|
||||
++ans; break;
|
||||
}
|
||||
}
|
||||
for(int i=1; i<=N; ++i) if(!match[i] && bfs(i)) ++ans;
|
||||
return ans;
|
||||
}
|
||||
28
source/Graph/TarjanSCC.cpp
Normal file
28
source/Graph/TarjanSCC.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
vi adj[N];
|
||||
int in[N], c = 0;
|
||||
stack<int> p;
|
||||
bool fin[N]; int scn[N], nscc = 0;
|
||||
int dfs(int s) {
|
||||
in[s] = ++c;
|
||||
p.push(s);
|
||||
|
||||
int m = c;
|
||||
for(auto i : adj[s]) {
|
||||
if(in[i] == 0) m = min(m, dfs(i));
|
||||
else if(!fin[i]) m = min(m, in[i]);
|
||||
}
|
||||
|
||||
if(m == in[s]) {
|
||||
nscc++;
|
||||
while(p.top() != s)
|
||||
{
|
||||
int i = p.top(); p.pop();
|
||||
scn[i] = nscc; fin[i] = true;
|
||||
}
|
||||
p.pop();
|
||||
scn[s] = nscc; fin[s] = true;
|
||||
}
|
||||
return m;
|
||||
}
|
||||
|
||||
forr(i, n) if(!fin[i]) dfs(i);
|
||||
Reference in New Issue
Block a user