图论
-
\(k\) 短路
-
圆方树
int n,nn;
struct {
Vi e[N];
void adde(int x,int y) { e[x].pb(y), e[y].pb(x); }
} tr;
struct {
int ind,dfn[N],low[N];
bool cut[N];
Vi e[N];
void tarjan(int rt,int u) {
static int t,s[N];
dfn[u] = low[u] = ++ind, s[++t] = u;
int son = 0;
for(int v : e[u])
if( dfn[v] ) ckmin(low[u],dfn[v]);
else {
tarjan(rt,v), ckmin(low[u],low[v]);
if( dfn[u] <= low[v] ) {
if( u != rt || son++ ) cut[u] = 1;
++nn, tr.adde(nn,u);
do tr.adde(nn,s[t]); while( v != s[t--] );
}
}
}
void main() {
For(i,1,n) if( !dfn[i] ) tarjan(i,i);
}
} G;
- SCC 缩点
int nn,ind,dfn[N],low[N],id[N];
Vi scc[N],ee[N];
void tarjan(int u) {
static int t,s[N];
dfn[u] = low[u] = ++ind, s[++t] = u, id[u] = -1;
for(auto [v,w] : e[u])
if( !dfn[v] ) tarjan(v), ckmin(low[u], low[v]);
else if( !~id[v] ) ckmin(low[u], dfn[v]);
if( dfn[u] == low[u] ) {
++nn;
do id[s[t]] = nn, scc[nn].pb(s[t]); while( u != s[t--] );
}
}
signed main() {
For(i,1,n) if( !dfn[i] ) tarjan(i);
For(u,1,n) for(int v : e[u]) if( id[u] != id[v] ) ee[id[u]].pb(id[v]);
}
树
- Prufer 序列
\(n\) 个点的完全图的生成树 \(\leftrightarrow\) 长度为 \(n-2\) 值域为 \([1,n]\) 的序列
// tree -> prufer
For(i,1,n-1) ++deg[fa[i]];
for(int i = 1, u = 1; i <= n-2; ++i, ++u) {
while( deg[u] ) ++u; p[i] = fa[u];
for(; i <= n-2 && !--deg[p[i]] && p[i] < u; ++i) p[i+1] = fa[p[i]];
}
// prufer -> tree
For(i,1,n-2) ++deg[p[i]]; p[n-1] = n;
for(int i = 1, u = 1; i < n; ++i, ++u) {
while( deg[u] ) ++u; fa[u] = p[i];
for(; i < n && !--deg[p[i]] && p[i] < u; ++i) fa[p[i]] = p[i+1];
}
- ST 表 LCA
int n,rt,dfn[N],st[][N];
Vi e[N];
int _min(int u,int v) { return dfn[u]<dfn[v] ? u : v; }
void dfs(int u,int fa) {
static int ind;
dfn[u] = ++ind, st[0][ind] = fa;
for(int v : e[u]) if( v != fa ) dfs(v,u);
}
int lca(int u,int v) {
if( u == v ) return u;
if( (u=dfn[u]) > (v=dfn[v]) ) swap(u,v);
int k = __lg(v-u++);
return _min(st[k][u],st[k][v-(1<<k)+1]);
}
signed main() {
dfs(rt,0);
For(i,1,) For(j,1,n-(1<<i)+1) st[i][j] = _min(st[i-1][j],st[i-1][j+(1<<i-1)]);
}
-
tarjan LCA
-
虚树
namespace T {
int dfn[N];
int lca(int x,int y) {}
}
namespace VT {
using namespace T;
bool is1[N];
Vi v2,e[N];
void adde(int x,int y) { e[x].pb(y), e[y].pb(x); }
void main(Vi &v1) {
{ // build
v1.resize(read()); for(int &i : v1) cin>>i, is1[i] = 1;
auto cmp = [](int x,int y) { return dfn[x] < dfn[y]; };
v2 = v1, sort(all(v2),cmp);
Rep(i,1,sz(v1)) v2.pb(lca(v2[i-1],v2[i]));
v2.pb(1), sort(all(v2),cmp), v2.erase(unique(all(v2)),v2.end());
Rep(i,1,sz(v2)) adde(lca(v2[i-1],v2[i]),v2[i]);
}
{ // clear
for(int i : v1) is1[i] = 0;
for(int i : v2) e[i].clear();
}
}
}
网络流
- 最大流/最小割
流量 long long
namespace flow {
const int N = ;
const LL inf = 0x3f3f3f3f3f3f3f3f;
int fn,S,T,head[N],dis[N];
struct Edge {
int to,b; LL c;
Edge(int to=0,int b=0,LL c=0):to(to),b(b),c(c){}
}; vector<Edge> e[N];
void init() { S = 1, T = fn = 2; }
void addedge(int x,int y,LL z) { e[x].pb(y,sz(e[y]),z), e[y].pb(x,sz(e[x])-1,0); }
bool bfs() {
static int l,r,q[N];
memset(head+1,0,sizeof(int)*fn), memset(dis+1,0,sizeof(int)*fn);
dis[S] = 1, q[l=r=1] = S;
while( l <= r ) {
int u = q[l++];
for(auto [v,b,c] : e[u]) if( c && !dis[v] )
{ dis[v] = dis[u]+1, q[++r] = v; if( v == T ) return 1; }
}
return 0;
}
LL dfs(int u,LL f) {
if( u == T ) return f;
LL use = 0;
for(int &i = head[u]; i < sz(e[u]); ++i)
if(auto &[v,b,c] = e[u][i]; c && dis[u]+1 == dis[v] ) {
if( LL g = dfs(v,min(c,f-use)) ) {
c -= g, e[v][b].c += g;
if( (use+=g) == f ) return f;
} else dis[v] = 0;
}
return use;
}
LL dinic() { LL mf=0; while( bfs() ) mf += dfs(S,inf); return mf; }
} using flow::fn; using flow::S; using flow::T; using flow::addedge;
- 最小费用最大流
流量 int
,费用 long long
namespace flow {
const int N = , inf = 0x3f3f3f3f; const LL infl = 0x3f3f3f3f3f3f3f3f;
int fn,S,T,mf,mc,head[N],dep[N]; LL dis[N];
bitset<N> vis;
struct Edge {
int to,b,c; LL w;
Edge(int to=0,int b=0,int c=0,LL w=0):to(to),b(b),c(c),w(w){}
}; vector<Edge> e[N];
void init() { S = 1, T = fn = 2; }
void addedge(int x,int y,int z=1,LL w=0)
{ e[x].pb(y,sz(e[y]),z,w), e[y].pb(x,sz(e[x])-1,0,-w); }
bool spfa() {
static queue<int> q;
memset(head+1,0,sizeof(int)*fn), memset(dis+1,0x3f,sizeof(dis[0])*fn);
dis[S] = 0, q.emplace(S);
while( q.size() ) {
int u = q.front(); q.pop(); vis[u] = 0;
for(auto& [v,b,c,w] : e[u]) if( c && dis[u]+w < dis[v] ) {
dis[v] = dis[u]+w, dep[v] = dep[u]+1;
if( !vis[v] ) vis[v] = 1, q.emplace(v);
}
}
return dis[T] < infl;
}
int dfs(int u,int f) {
if( u == T ) return f;
int use = 0;
for(int &i = head[u]; i < sz(e[u]); ++i) {
auto& [v,b,c,w] = e[u][i];
if( c && dis[u]+w == dis[v] && dep[u]+1 == dep[v] ) {
if( int g = dfs(v,min(c,f-use)) ) {
c -= g, e[v][b].c += g;
if( (use+=g) == f ) break;
} else dis[v] = -1;
}
}
return use;
}
void dinic() { while( spfa() ) { int f = dfs(S,inf); mf += f, mc += f * dis[T]; } }
} using flow::fn; using flow::S; using flow::T; using flow::addedge;
- 负圈最小费用最大流
有源汇上下界
namespace flow {
const int N = , inf = 0x3f3f3f3f; const LL infl = 0x3f3f3f3f3f3f3f3f;
int s,t,fn,S,T,mf,mc,dlt[N],head[N],dep[N]; LL dis[N];
bitset<N> vis;
struct Edge {
int to,b,c; LL w;
Edge(int to=0,int b=0,int c=0,LL w=0):to(to),b(b),c(c),w(w){}
}; vector<Edge> e[N];
void addedge(int x,int y,int z=1,LL w=0) {
auto adde=[](int x,int y,int z,LL w)
{ e[x].pb(y,sz(e[y]),z,w), e[y].pb(x,sz(e[x])-1,0,-w); };
if( w >= 0 ) adde(x,y,z,w);
else mc += z*w, adde(y,x,z,-w), dlt[x] -= z, dlt[y] += z;
}
void main() {
For(i,1,fn)
if( dlt[i] > 0 ) addedge(S,i,dlt[i]);
else if( dlt[i] < 0 ) addedge(i,T,-dlt[i]);
addedge(t,s,inf);
dinic();
mf = 0, S = s, T = t, dinic();
}
} using flow::fn; using flow::S; using flow::T; using flow::addedge;
标签:图论,int,LL,pb,v2,dfn,模板,dis
From: https://www.cnblogs.com/ft61/p/18327973