【模板】图论

二分图

二分图最大匹配(匈牙利)
//P3386 【模板】二分图最大匹配
#include <bits/stdc++.h>
using namespace std;
const int N=510,M=5e4+10;
int n,m,e,vis[N],match[N];
int mp[N][N];

bool dfs( int x )
{
        for ( int i=1; i<=m; i++ )3
                if ( mp[x][i] && !vis[i] )
                {
                        vis[i]=1;
                        if ( !match[i] || dfs( match[i] ) ) { match[i]=x; return 1;}
                }
        return 0;
}

int main()
{
        memset( mp,0,sizeof(mp) ); memset( vis,0,sizeof(vis) );
        memset( match,0,sizeof(match) );
        
        scanf( "%d%d%d",&n,&m,&e );
        for ( int i=1,u,v; i<=e; i++ )
                scanf( "%d%d",&u,&v ),mp[u][v]=1;

        int cnt=0;
        for ( int i=1; i<=n; i++ )
        {
                memset( vis,0,sizeof(vis) );
                if ( dfs(i) ) cnt++;
        }

        printf( "%d",cnt );
}
二分图最大带权匹配(KM)
//Author: RingweEH
//P6577 KM算法
const int N=510;
const ll inf=0x7f7f7f7f;
int n,m,match[N],visa[N],visb[N],pas[N];
ll edge[N][N],del[N],vala[N],valb[N],c[N];

void bfs( int u )
{
    int a,v=0,vl=0,delta;
    for ( int i=1; i<=n; i++ )
        pas[i]=0,c[i]=inf;
    match[v]=u;
    do
    {
        a=match[v]; delta=inf; visb[v]=1;
        for ( int b=1; b<=n; b++ )
            if ( !visb[b] )
            {
                if ( c[b]>vala[a]+valb[b]-edge[a][b] )
                    c[b]=vala[a]+valb[b]-edge[a][b],pas[b]=v;
                if ( c[b]<delta ) delta=c[b],vl=b;
            }
        for ( int b=0; b<=n; b++ )
            if ( visb[b] ) vala[match[b]]-=delta,valb[b]+=delta;
            else c[b]-=delta;
        v=vl;
    }while ( match[v] );
    while ( v ) match[v]=match[pas[v]],v=pas[v];
}

ll KM()
{
    for ( int i=1; i<=n; i++ )
        match[i]=vala[i]=valb[i]=0;
    for ( int u=1; u<=n; u++ )
    {
        for ( int v=1; v<=n; v++ )
            visb[v]=0;
        bfs( u );
    }
    ll res=0;
    for ( int u=1; u<=n; u++ )
        res+=edge[match[u]][u];
    return res;
}

int main()
{
    n=read(); m=read();
    for ( int u=1; u<=n; u++ )
        for ( int v=1; v<=n; v++ )
            edge[u][v]=-inf;
    for ( int i=1; i<=m; i++ )
    {
        int u=read(),v=read(); ll w=read();
        edge[u][v]=max( edge[u][v],w );
    }

    printf( "%lld\n",KM() );
    for ( int u=1; u<=n; u++ )
        printf( "%d ",match[u] );
    
    return 0;
}
稳定婚姻问题
//Author: RingweEH
//稳定婚姻问题模板,POJ3487
const int N=40;
int lef[N],list_lr[N][N],list_rl[N][N],nxt_l[N];
int match_l[N],match_r[N],n;
queue<int> q;

void get_match( int le,int ri )
{
    int now=match_r[ri];
    if ( now )
    {
        match_l[now]=0; q.push( now );
    }
    match_r[ri]=le; match_l[le]=ri;
}

int main()
{
    ios::sync_with_stdio(0);
    int T=read();
    while ( T-- )
    {
        memset( lef,0,sizeof(lef) );
        cin>>n; char ch;
        for ( int i=0; i<n; i++ )
        {
            cin>>ch; lef[ch-'a'+1]=1;
        }
        for ( int i=0; i<n; i++ )
            cin>>ch;
        char s[N];
        for ( int i=0; i<n; i++ )
        {
            cin>>s; int c=s[0]-'a'+1;
            for ( int j=2; s[j]; j++ )
                list_lr[c][j-1]=s[j]-'A'+1;
            nxt_l[c]=1; match_l[c]=0;
            q.push( c ); 
        }
        for ( int i=0; i<n; i++ )
        {
            cin>>s; int c=s[0]-'A'+1;
            for ( int j=2; s[j]; j++ )
                list_rl[c][s[j]-'a'+1]=j-1;
            match_r[c]=0;
        }
        //-------------Input Finished.--------------
        while ( !q.empty() )
        {
            int now=q.front(); q.pop();
            int rnow=list_lr[now][nxt_l[now]++];
            if ( !match_r[rnow] ) get_match( now,rnow );
            else if ( list_rl[rnow][now]<list_rl[rnow][match_r[rnow]] ) get_match( now,rnow );
            else q.push( now );
        }
        //-------------Matched---------------
        for ( int i=1; i<35; i++ )
            if ( lef[i] ) cout<<(char)(i-1+'a')<<' '<<(char)(match_l[i]+'A'-1)<<endl;
        if ( T ) cout<<endl;
    }

    return 0;
}
2-SAT
//P4782 【模板】2-SAT 问题
#include <bits/stdc++.h>
using namespace std;
const int N=2e6+10;
struct edge
{
	int to,nxt;
}e[N];
int n,m,tot=0,head[N];
int low[N],dfn[N],cnt=0,bel[N],scc=0;
stack<int> sta;
void add( int u,int v )
{
	tot++; e[tot].to=v; e[tot].nxt=head[u]; head[u]=tot;
}

void tarjan( int x )
{
	dfn[x]=low[x]=++cnt; sta.push(x);
	for ( int i=head[x]; i; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( !dfn[y] )
		{
			tarjan( y ); low[x]=min( low[x],low[y] );
			
		}
		else if ( !bel[y] ) low[x]=min( low[x],dfn[y] );
	}
	if ( dfn[x]==low[x] )
	{
		scc++;
		while ( 1 )
		{
			int y=sta.top(); sta.pop();
			bel[y]=scc;
			if ( y==x ) break;
		}
	}
}

int main()
{
	scanf( "%d%d",&n,&m );
	while ( m-- )
	{
		int i,j,a,b; scanf( "%d%d%d%d",&i,&a,&j,&b );
		add( i+(1-a)*n,j+b*n ); add( j+(1-b)*n,i+a*n );
	}
	
	for ( int i=1; i<=2*n; i++ )
		if ( !dfn[i] ) tarjan( i );
	for ( int i=1; i<=n; i++ )
		if ( bel[i]==bel[i+n] ) { printf( "IMPOSSIBLE" ); return 0; }
	printf( "POSSIBLE\n" );
	for ( int i=1; i<=n; i++ )
		printf( "%d ",bel[i]>bel[i+n] );
	//强联通分量编号越小 -> 拓扑序越大 -> 越优 
	
	return 0;
}

LCA

Code
//树剖 
#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=5e5+10;
struct edge
{
    int to,nxt;
}e[maxn*2];
struct leaf
{
	int dep,siz,son,top,fa;
}tree[maxn];
int head[maxn],n,m,s,ecnt;

void add( int x,int y )  
{
	e[++ecnt].to=y; e[ecnt].nxt=head[x]; head[x]=ecnt;
} 

void dfs1( int x )
{
	tree[x].siz=1; tree[x].dep=tree[tree[x].fa].dep+1;
	for ( int i=head[x]; i; i=e[i].nxt )
	{
		int d=e[i].to; 
		if ( d==tree[x].fa ) continue;
		tree[d].fa=x; dfs1( d );
		tree[x].siz+=tree[d].siz;
		if ( !tree[x].son || tree[tree[x].son].siz<tree[d].siz ) tree[x].son=d;
	}
}

void dfs2( int x,int tv )
{
	tree[x].top=tv;
	if ( tree[x].son ) dfs2( tree[x].son,tv );
	for ( int i=head[x]; i; i=e[i].nxt )
	{
		int d=e[i].to;
		if ( d==tree[x].fa || d==tree[x].son ) continue;
		dfs2( d,d );
	}
}

int main()
{
	scanf( "%d%d%d",&n,&m,&s );
	for ( int i=1; i<n; i++ )
	{
		int x,y;
		scanf( "%d%d",&x,&y );
		add( x,y ); add( y,x );
	}
	
	dfs1( s ); dfs2( s,s );
	for ( int i=1; i<=m; i++ )
	{
		int x,y;
		scanf( "%d%d",&x,&y );
		while ( tree[x].top!=tree[y].top )
		{
			if ( tree[tree[x].top].dep>=tree[tree[y].top].dep ) x=tree[tree[x].top].fa;
			else y=tree[tree[y].top].fa;
		}
		
		printf( "%d\n",tree[x].dep<tree[y].dep ? x:y );
	}
}

/*
倍增 

//Author: RingweEH
void init()
{
    memset( fa,0,sizeof(fa) ); memset( dep,0,sizeof(dep) );
}

void dfs( int u,int fat )
{
    dep[u]=dep[fat]+1; fa[u][0]=fat;
    for ( int i=head[u]; i; i=e[i].nxt )
    {
        int v=e[i].to;
        if ( v==fat ) continue;
        dfs( v,u );
    }
}

int LCA( int x, int y ) 
{
	if ( dep[x]<dep[y] ) swap(x, y);
    for ( int i=19; i>=0; i-- )
        if ( dep[fa[x][i]]>=dep[y] ) x=fa[x][i];
	if ( x==y ) return x;
	for ( int k=19; k>=0; k-- )
		if ( fa[x][k]!=fa[y][k] ) x=fa[x][k],y=fa[y][k];
	return fa[x][0];
}

int main()
{
    init(); dfs( rt,0 );
    for ( int j=1; j<=19; j++ )
     for ( int i=1; i<=n; i++ )
        if ( fa[i][j-1] ) fa[i][j]=fa[fa[i][j-1]][j-1];
}
*/

Tarjan

割边
//ZOJ 2588 Burning Bridges
//【模板】割边 
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+10,M=1e5+10;
struct edge
{
	int to,nxt; int id;
}e[M<<1];
int n,m,tot,head[N],dfn[N],low[N],cnt=0;
int num,ans[M];

void add( int u,int v,int id )
{
	tot++; e[tot].to=v; e[tot].nxt=head[u]; head[u]=tot; 
	e[tot].id=id;
}

void tarjan( int x,int pre )
{
	dfn[x]=low[x]=++cnt;
	for ( int i=head[x]; i; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( i==pre ) continue;
		
		if ( !dfn[y] )
		{
			tarjan(y,i^1); low[x]=min( low[x],low[y] );
			if ( low[y]>dfn[x] )  ans[++num]=e[i].id;
		}
		else low[x]=min( low[x],dfn[y] );
	}
} 

int main()
{
	int T; scanf( "%d",&T );
	while ( T-- )
	{
		tot=1; cnt=num=0; memset( dfn,0,sizeof(dfn) );
		memset( head,0,sizeof(head) );
		memset( low,0,sizeof(low) );
		
		scanf( "%d%d",&n,&m );
		for ( int i=1,u,v; i<=m; i++ )
			scanf( "%d%d",&u,&v ),add( u,v,i ),add( v,u,i );
			
		tarjan( 1,-1 );	
		//因为题目中保证联通,所以一次就够了 
		sort( ans+1,ans+1+num );
		printf( "%d\n",num );
		if ( num==0 ) { printf( "\n" ); continue; }
		printf( "%d",ans[1] );
		for ( int i=2; i<=num; i++ )
			printf( " %d",ans[i] );
		printf( "\n" );
		if ( T ) printf( "\n" );
	}
}
割点
//P3388 【模板】割点(割顶)
#include <bits/stdc++.h>
using namespace std;
const int N=2e4+10,M=1e5+10;
struct edge
{
	int to,nxt;
}e[M<<1];
int n,m,tot=0,head[N],dfn[N],low[N],cnt=0,rt,ans=0;
bool cut[N]={0};

void add( int u,int v )
{
	tot++; e[tot].to=v; e[tot].nxt=head[u]; head[u]=tot;
}

void tarjan( int x )
{
	dfn[x]=low[x]=++cnt; int fl=0;
	for ( int i=head[x]; i; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( !dfn[y] )
		{
			tarjan( y ); low[x]=min( low[x],low[y] );
			if ( low[y]>=dfn[x] )
			{
				fl++; if ( x!=rt || fl>1 ) cut[x]=1;
			}
		}
		else low[x]=min( low[x],dfn[y] );
	}				
}

int main()
{
	scanf( "%d%d",&n,&m );
	for ( int i=1,u,v; i<=m; i++ )	
	{
		scanf( "%d%d",&u,&v );
		if ( u==v ) continue;
		add( u,v ),add( v,u );
	}
	
	memset( dfn,0,sizeof(dfn) );
	for ( int i=1; i<=n; i++ )
		if ( !dfn[i] ) rt=i,tarjan(i);
		
	for ( int i=1; i<=n; i++ )
		if ( cut[i] ) ans++;
	printf( "%d\n",ans );
	for ( int i=1; i<=n; i++ )
		if ( cut[i] ) printf( "%d ",i );
}
SCC缩点
//P2341 [USACO03FALL][HAOI2006]受欢迎的牛 G
//【模板】强连通分量缩点(SCC) 
#include <bits/stdc++.h>
using namespace std;
const int N=1e4+5,M=5e4+10;
struct edge
{
	int to,nxt;
}e[M];
int n,m,ans,tot,head[N],deg[N],siz[N];
int dfn[N],low[N],cnt,scc,bel[N];
stack<int> sta;

void add( int u,int v )
{
	e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot;
}

void tarjan( int x )
{
	dfn[x]=low[x]=++cnt; sta.push(x);
	for ( int i=head[x]; i; i=e[i].nxt )
	{
		int y=e[i].to;
		if ( !dfn[y] )
		{
			tarjan( y ); low[x]=min( low[x],low[y] );
		}
		else if ( !bel[y] ) low[x]=min( low[x],dfn[y] );
	}
	if ( dfn[x]==low[x] )
	{
		scc++;
		while ( 1 )
		{
			int y=sta.top(); sta.pop();
			bel[y]=scc; siz[scc]++;
			if ( y==x ) break;
		}
	}
}

int main()
{
	ans=tot=cnt=scc=0; memset( head,0,sizeof(head) );
	memset( dfn,0,sizeof(dfn) );
	
	scanf( "%d%d",&n,&m );
	for ( int i=1,u,v; i<=m; i++ )
		scanf( "%d%d",&u,&v ),add( u,v );
	
	for ( int i=1; i<=n; i++ )
		if ( !dfn[i] ) tarjan( i );
	for ( int x=1; x<=n; x++ )
	 for ( int i=head[x]; i; i=e[i].nxt )
	 {
	 	int y=e[i].to;
	 	if ( bel[x]==bel[y] ) continue;
	 	deg[bel[x]]++;
	 }
	for ( int i=1; i<=scc; i++ )
		if ( deg[i]==0 )
		{
			if ( ans ) { ans=0; break; }
			ans+=siz[i];
		}
		
	printf( "%d",ans );
}

最短路

Dijkstra
/*
算法:最短路  Dijkstra 模板(邻接表) 
思路:
1. 初始化dis[1]=0, 其余0x3f
2. 找一个没标记且dis最小的点x,标记
3. 扫描x的出边(x,y,z),若dis[y]>dis[x]+z,更新
4. 重复直到标记完 
*/ 
#include <bits/stdc++.h>
using namespace std;
const int N=100100,M=5e6+10,inf=2147483647;
struct node
{
	int ver,nxt,edge;
}e[M];		//是m不是n,要看tot的大小 
int head[M],dis[N],n,m,s,tot=0;
bool vis[N]={0};

void add( int x,int y,int z )
{
	++tot; e[tot].ver=y; e[tot].edge=z; e[tot].nxt=head[x]; head[x]=tot; 
}

void getdis( int s )
{
	int p=s; 
	while ( !vis[p] )
	{
		vis[p]=1;
		for ( int i=head[p]; i; i=e[i].nxt )
		{
			int y=e[i].ver,z=e[i].edge;
			if ( dis[y]>dis[p]+z && !vis[y] ) dis[y]=dis[p]+z;
		} 
		int mmin=inf;
		for ( int i=1; i<=n; i++ )
			if ( dis[i]<mmin && !vis[i] ) mmin=dis[i],p=i;
	}
}

int main()
{
	scanf( "%d%d%d",&n,&m,&s );
	for ( int i=1; i<=m; i++ )
	{
		int u,v,w;
		scanf( "%d%d%d",&u,&v,&w );
		add( u,v,w );
	}
	
	for ( int i=1; i<=n; i++ )
		dis[i]=inf;
	dis[s]=0; 
	getdis( s );
	
	for ( int i=1; i<=n; i++ )
		printf( "%d ",dis[i] );
			
}

点分治

点分治
//Author: RingweEH
//POJ1741 Tree
const int N=1e4+10,INF=0x3f3f3f3f;
struct Edge{ int to,nxt,val; }e[N<<1];
int n,k,head[N],tot,siz[N],dep[N],rt,mx[N],All;
int dis[N],cnt,ans;
bool vis[N];

void Adde(int u,int v,int w){e[++tot].to=v;e[tot].nxt=head[u];e[tot].val=w;head[u]=tot;}
void GetRt( int u,int fat )
{
    mx[u]=0; siz[u]=1;
    for ( int i=head[u]; i; i=e[i].nxt )
    {
        int v=e[i].to; if ( v==fat || vis[v] ) continue;
        GetRt(v,u); siz[u]+=siz[v]; bmax(mx[u],siz[v]);
    }
    bmax(mx[u],All-siz[u]);
    if ( mx[rt]>mx[u] ) rt=u;
}
void GetDis( int u,int fat )
{
    dis[++cnt]=dep[u];
    for ( int i=head[u]; i; i=e[i].nxt )
    {
        int v=e[i].to; if ( v==fat || vis[v] ) continue;
        dep[v]=dep[u]+e[i].val; GetDis(v,u);
    }
}
int Calc( int u )
{
    cnt=0; GetDis(u,0); sort(dis+1,dis+1+cnt);
    int i=1,j=cnt,res=0;
    while ( i<j )
        if ( dis[i]+dis[j]<=k ) res+=j-i,i++;
        else j--;
    return res;
}
void Work( int u )
{
    dep[u]=0; vis[u]=1; ans+=Calc(u);
    for ( int i=head[u]; i; i=e[i].nxt )
    {
        int v=e[i].to; if ( vis[v] ) continue;
        dep[v]=e[i].val; ans-=Calc(v);
        All=siz[v]; rt=0; GetRt(v,0); Work(rt);
    }
}

int main()
{
//freopen( "exam.in","r",stdin );

    n=read(); k=read();
    while ( n )
    {
        tot=0; memset( head,0,sizeof(head) );
        ans=0; memset( vis,0,sizeof(vis) );

        for ( int i=1,u,v,w; i<n; i++ ) 
            u=read(),v=read(),w=read(),Adde(u,v,w),Adde(v,u,w);

        mx[0]=INF; All=n; rt=0; GetRt(1,0); Work(rt);

        printf("%d\n",ans ); n=read(); k=read();
    }

    return 0;
}
动态淀粉质(点分树)

//P6329 【模板】点分树 | 震波
#include <bits/stdc++.h>
#define lowbit(x) ((x)&(-x)) 
using namespace std;
const int N=1e5+10,inf=1e9+7;
struct edge
{
        int to,nxt;
}e[N<<1];
int n,m,head[N],val[N],fa[N][20],dis[N][20],sz[N],f[N],dep[N],rt,siz,tot=0;
bool vis[N];
vector<int> sbit[N],fbit[N];

void add( int u,int v )
{
        e[++tot]=(edge){v,head[u]}; head[u]=tot;
        e[++tot]=(edge){u,head[v]}; head[v]=tot;
}

void get_rt( int x,int fat )
{
        sz[x]=1; f[x]=0;
        for ( int i=head[x]; i; i=e[i].nxt )
        {
                int y=e[i].to;
                if ( vis[y] || fat==y ) continue;
                get_rt( y,x ); sz[x]+=sz[y]; f[x]=max( f[x],sz[y] );
        }
        f[x]=max( f[x],siz-sz[x] );
        if ( f[x]<f[rt] ) rt=x;
}

void pre_build( int x,int ancestor,int fat,int d )
{
        for ( int i=head[x]; i; i=e[i].nxt )
        {
                int y=e[i].to;
                if ( vis[y] || y==fat ) continue;
                fa[y][++dep[y]]=ancestor; dis[y][dep[y]]=d;
                pre_build( y,ancestor,x,d+1 );
        }
}

void build( int x )
{
        vis[x]=1; pre_build( x,x,0,1 );
        int sav=siz; sbit[x].resize( siz+1 ); fbit[x].resize( siz+1 );
        for ( int i=head[x]; i; i=e[i].nxt )
        {
                int y=e[i].to; if ( vis[y] ) continue;
                siz=sz[y];  if ( siz>sz[x] ) siz=sav-sz[x];
                rt=0; get_rt( y,x ); build( rt );
        }
}

int qsum_s( int x,int k )
{
        int res=val[x],lim=sbit[x].size()-1; k=min( k,lim );
        for ( int i=k; i; i-=lowbit(i) )  res+=sbit[x][i];
        return res;
}

int qsum_f( int x,int k )
{
        int res=0,lim=fbit[x].size()-1; k=min( k,lim );
        for ( int i=k; i; i-=lowbit(i) ) res+=fbit[x][i];
        return res;
}

void modify( int x,int v )
{
        int d=dis[x][dep[x]],lim=sbit[x].size()-1;
        for ( int j=d; j<=lim && j; j+=lowbit(j) ) fbit[x][j]+=v;
        for ( int i=dep[x]; i; i-- )
        {
                d=dis[x][i]; lim=sbit[fa[x][i]].size()-1;
                for ( int j=d; j<=lim; j+=lowbit(j) ) sbit[fa[x][i]][j]+=v;
                d=dis[x][i-1];
                for ( int j=d; j<=lim && j; j+=lowbit(j) ) fbit[fa[x][i]][j]+=v;
        }
}

int query( int x,int k )
{
        int res=qsum_s( x,k );
        for ( int i=dep[x]; i; i-- )
                if ( dis[x][i]<=k ) res+=qsum_s( fa[x][i],k-dis[x][i] )-qsum_f( fa[x][i+1],k-dis[x][i] );
        return res;
}

int main()
{
        scanf( "%d%d",&n,&m );
        for ( int i=1; i<=n; i++ )
                scanf( "%d",&val[i] );
        for ( int i=1,u,v; i<n; i++ )
                scanf( "%d%d",&u,&v ),add( u,v );
        
        f[0]=inf; siz=n; get_rt( 1,0 ); build( rt );
        for ( int i=1; i<=n; i++ )
                fa[i][dep[i]+1]=i;
        for ( int i=1; i<=n; i++ )
                modify( i,val[i] );
        int las=0;
        while ( m-- )
        {
                int opt,x,y; scanf( "%d%d%d",&opt,&x,&y ); 
                x^=las; y^=las;
                if ( opt==0 ) las=query( x,y ),printf( "%d\n",las );
                else modify( x,y-val[x] ),val[x]=y;
        }
}

网络流

最大流

Dinic
//Author:RingweEH
//P3376 【模板】网络最大流
const int N=210,M=5e3+10;
const ll INF=0x7f7f7f7f;
struct Edge
{
	int to,nxt; ll val;
}e[M<<1];
int n,m,S,T,tot=1,nw[N],head[N];
ll mxflow,dis[N];

void Add( int u,int v,ll w )
{
	e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].val=w;
	e[++tot].to=u; e[tot].nxt=head[v]; head[v]=tot; e[tot].val=0;
}

bool BFS()		//构建分层图,判断残量网络还能不能到达汇点
{
	for ( int i=1; i<=n; i++ )
		dis[i]=INF;
	queue<int> q; q.push( S ); dis[S]=0; nw[S]=head[S];
	while ( !q.empty() )
	{
		int u=q.front(); q.pop();
		for ( int i=head[u]; i; i=e[i].nxt )
		{
			int v=e[i].to;
			if ( e[i].val>0 && dis[v]==INF )
			{
				q.push( v ); nw[v]=head[v]; dis[v]=dis[u]+1;
				if ( v==T ) return 1;
			}
		}
	}
	return 0;
}

int DFS( int u,ll sum )		//sum记录增广路上的最小容量
{
	if ( u==T ) return sum;
	ll res=0;
	for ( int i=nw[u]; i && sum; i=e[i].nxt )
	{
		nw[u]=i; int v=e[i].to;
		if ( e[i].val>0 && (dis[v]==dis[u]+1) )
		{
			ll tmp=DFS( v,min(sum,e[i].val) );
			if ( tmp==0 ) dis[v]=INF;	//v不能再增广了,剪枝
			e[i].val-=tmp; e[i^1].val+=tmp;
			res+=tmp; sum-=tmp;		//res是经过该点的流量和,sum是经过该点剩余流量
		}
	}
	return res;
}

int main()
{
	n=read(); m=read(); S=read(); T=read();
	for ( int i=1; i<=m; i++ )
	{
		int u=read(),v=read(); ll w=read();
		Add( u,v,w );
	}

	while ( BFS() ) mxflow+=DFS(S,INF);

	printf( "%lld\n",mxflow );

	return 0;
}
EK
//Author:RingweEH
//P3376 【模板】网络最大流
const int N=210,M=5e3+10;
const ll INF=0x7f7f7f7f;
struct Edge
{
	int to,nxt; ll val;
}e[M<<1];
int n,m,S,T,tot=1,head[N],pre[N],mp[N][N];
ll mxflow,dis[N];
bool vis[N];

void Add( int u,int v,int ll w )
{
	e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].val=w;
	e[++tot].to=u; e[tot].nxt=head[v]; head[v]=tot; e[tot].val=0;	//反向边
}

bool BFS()
{
	for ( int i=1; i<=n; i++ )
		vis[i]=0;
	queue<int> q; q.push( S ); vis[S]=1; dis[S]=INF;
	while ( !q.empty() )
	{
		int u=q.front(); q.pop();
		for ( int i=head[u]; i; i=e[i].nxt )
		{
			if ( e[i].val==0 ) continue;	//流没了
			int v=e[i].to;
			if ( vis[v] ) continue; 
			dis[v]=min( dis[u],e[i].val );	//取路径上的最小剩余容量
			pre[v]=i; 		//记录从哪条边过来
			q.push( v ); vis[v]=1;
			if ( v==T ) return 1;	//走到汇点了
		}
	}
	return 0;
}

void Update()		//每次找到一条增广路,并更新路径上的值
{
	int u=T;
	while ( u^S )
	{
		int v=pre[u];
		e[v].val-=dis[T]; e[v^1].val+=dis[T];		
		//这条增广路的流量,用来更新路径上所有边和反向边
		u=e[v^1].to;		//本来记录的是过来的边,回去要反向
	}
	mxflow+=dis[T];		//总流量增加
}

int main()
{
	n=read(); m=read(); S=read(); T=read();
	for ( int i=1; i<=m; i++ )
	{
		int u,v; ll w; u=read(); v=read(); w=read();
		if ( mp[u][v]==0 ) Add( u,v,w ),mp[u][v]=tot;
		else e[mp[u][v]-1].val+=w;
		//重边容量合并
	}

	while ( BFS() ) Update();

	printf( "%lld\n",mxflow ); 

	return 0;
}
ISAP
//Author:RingweEH
//P3376 【模板】网络最大流
const int N=210,M=5e3+10;
const ll INF=0x7f7f7f7f;
struct Edge
{
    int to,nxt; ll val;
}e[M<<1];
int n,m,S,T,tot=1,head[N],dep[N],gap[N],nw[N];
ll mxflow=0;

void Add( int u,int v,ll w )
{
    e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].val=w;
    e[++tot].to=u; e[tot].nxt=head[v]; head[v]=tot; e[tot].val=0;
}

void BFS()
{
    memset( dep,-1,sizeof(dep) ); memset( gap,0,sizeof(gap) );
    dep[T]=0; gap[0]=1;
    queue<int> q; q.push( T );
    while ( !q.empty() )
    {
        int u=q.front(); q.pop();
        for ( int i=head[u]; i; i=e[i].nxt )
        {
            int v=e[i].to;
            if ( dep[v]>-1 ) continue;
            q.push( v ); dep[v]=dep[u]+1; gap[dep[v]]++;
        }
    }
}

int DFS( int u,ll sum )
{
    if ( u==T ) { mxflow+=sum; return sum; }
    ll res=0;
    for ( int i=nw[u]; i; i=e[i].nxt )
    {
        nw[u]=i; int v=e[i].to;
        if ( e[i].val && dep[v]+1==dep[u] )
        {
            int tmp=DFS( v,min(e[i].val,sum) );
            if ( tmp )
            {
                e[i].val-=tmp; e[i^1].val+=tmp;
                sum-=tmp; res+=tmp;
            }
            if ( sum==0 ) return res;
        }
    }
    gap[dep[u]]--; 
    if ( gap[dep[u]]==0 ) dep[S]=n+1;
    dep[u]++; gap[dep[u]]++;
    return res;
}

int main()
{
    n=read(); m=read(); S=read(); T=read();
    for ( int i=1; i<=m; i++ )
    {
        int u=read(),v=read(); ll w=read();
        Add( u,v,w );
    }

    BFS(); mxflow=0;
    while ( dep[S]<n ) 
    {
        memcpy( nw,head,sizeof(head) );  DFS( S,INF );
    }

    printf( "%lld\n",mxflow );

    return 0;
}
HLPP预流推进
//Author:RingweEH
#define pb push_back
const int N=1203,INF=0x3f3f3f3f;
struct Edge
{
    int to,nxt,val;
    Edge ( int _to,int _nxt,int _val ) : to(_to),nxt(_nxt),val(_val) {}
};
vector<Edge> g[N];
int n,m,S,T,h[N],cnt[N],work,ht,rest[N];
vector<int> las[N],gap[N];

void Add( int u,int v,int w )
{
    g[u].pb( Edge(v,g[v].size(),w) );
    g[v].pb( Edge(u,g[u].size()-1,0) );
}

void Update_height( int u,int nw )
{
    ++work;         //work记录更改高度的次数
    if ( h[u]^INF ) --cnt[h[u]];
    h[u]=nw; 
    if ( nw==INF ) return;
    ++cnt[nw]; ht=nw; //cnt[i]记录高度为i的节点个数
    gap[nw].pb(u);          //gap[i]记录高度为i的节点
    if ( rest[u] ) las[nw].pb(u);   //las[i]记录高度为i且还有超额流的节点
}

void Relabel()      //重置高度
{
    work=0; memset( h,0x3f,sizeof(h) ); memset( cnt,0,sizeof(cnt) );
    for ( int i=0; i<=ht; i++ )
        las[i].clear(),gap[i].clear();
    h[T]=0; queue<int> q; q.push(T);
    while ( !q.empty() )        //每次重新BFS
    {
        int u=q.front(); q.pop();
        for ( Edge &e : g[u] )
            if ( h[e.to]==INF && g[e.to][e.nxt].val ) //如果还有流量且另一个端点没被更新过
            {
                q.push( e.to ); Update_height( e.to,h[u]+1 );   //设为到汇点的距离
            }
        ht=h[u];        //记录最大的一个高度
    }
}

void Push( int u,Edge &e )      //u的超额流通过边e往外流
{
    if ( rest[e.to]==0 ) las[h[e.to]].pb(e.to);     //如果没在里面,现在就要在了
    int del=min( rest[u],e.val );   
    e.val-=del; g[e.to][e.nxt].val+=del;
    rest[u]-=del; rest[e.to]+=del;
}

void Push_Flow( int u )
{
    int nh=INF;
    for ( Edge &e : g[u] )   
        if ( e.val )
            if ( h[u]==h[e.to]+1 )
            {
                Push( u,e );
                if ( rest[u]<=0 ) return;
            }
            else nh=min( nh,h[e.to]+1 );        
            //一边往外流一边以防万一要更新,收集最小值
    if ( cnt[h[u]]>1 ) Update_height( u,nh );       //没断层,直接更新
    else
        for ( int i=h[u]; i<N; i++ )        //断层了
        {
            for ( int j : gap[i] ) 
                Update_height( j,INF );
            gap[i].clear();
        }
}

int HLPP()
{
    memset( rest,0,sizeof(rest) );
    rest[S]=2147483647;
    Relabel();
    for ( Edge &e : g[S] )      //从源点往外推
        Push( S,e );
    for ( ; ~ht; --ht )
        while ( !las[ht].empty() )      //枚举高度,从高到底依次往外推
        {
            int u=las[ht].back(); las[ht].pop_back();
            Push_Flow( u );
            if ( work>20000 ) Relabel();        //如果改变得过多了那么就重新标记
        }
    return rest[T];
}

int main()
{
    n=read(); m=read(); S=read(); T=read();
    for ( int i=1,u,v,w; i<=m; i++ )
        u=read(),v=read(),w=read(),Add( u,v,w );
    printf( "%d\n",HLPP() );
}

最小费用最大流

SSP
//Author:RingweEH
//LOJ102
const int N=410,M=15010,INF=0x3f3f3f3f;
struct Edge
{
	int to,nxt,flow,cap;
	Edge ( int _to=0,int _nxt=0,int _flow=0,int _cap=0 ) :
	 	to(_to),nxt(_nxt),flow(_flow),cap(_cap) {}
}e[M<<1];
int n,m,S,T,tot=1,head[N];
int pre[N],dis[N],mxflow,mncost;
bool vis[N];

void Add( int u,int v,int fl,int cap )
{
	e[++tot]=Edge(v,head[u],fl,cap); head[u]=tot;
	e[++tot]=Edge(u,head[v],0,-cap); head[v]=tot;
}

bool BFS()
{
	for ( int i=1; i<=n; i++ )
		vis[i]=0,dis[i]=INF;
	queue<int> q; q.push( S ); dis[S]=0;
	while ( !q.empty() )
	{
		int u=q.front(); q.pop(); vis[u]=0;
		for ( int i=head[u]; i; i=e[i].nxt )
		{
			int v=e[i].to; 
			if ( dis[v]>dis[u]+e[i].cap && e[i].flow )
			{
				dis[v]=dis[u]+e[i].cap; pre[v]=i;
				if ( !vis[v] ) vis[v]=1,q.push( v );
			}
		}
	}
	return dis[T]!=INF;
}

void Update()
{
	int mn=INF;
	for ( int i=T; i^S; i=e[pre[i]^1].to )
		bmin( mn,e[pre[i]].flow );
	for ( int i=T; i^S; i=e[pre[i]^1].to )
	{
		e[pre[i]].flow-=mn; e[pre[i]^1].flow+=mn;
		mncost+=mn*e[pre[i]].cap;
	}
	mxflow+=mn;
}

int main()
{
	n=read(); m=read(); S=1; T=n;
	for ( int i=1,u,v,f,c; i<=m; i++ )
		u=read(),v=read(),f=read(),c=read(),Add( u,v,f,c );

	while ( BFS() ) Update();

	printf( "%d %d\n",mxflow,mncost );
}
类Dinic
//Author:RingweEH
const int N=410,M=15010,INF=0x3f3f3f3f;
struct Edge
{
	int to,nxt,flow,cap;
	Edge ( int _to=0,int _nxt=0,int _flow=0,int _cap=0 ) :
	 	to(_to),nxt(_nxt),flow(_flow),cap(_cap) {}
}e[M<<1];
int n,m,S,T,tot=1,head[N],dis[N],mxflow,mncost,nw[N];
bool vis[N];
 
void Add( int u,int v,int fl,int cap )
{
	e[++tot]=Edge(v,head[u],fl,cap); head[u]=tot;
	e[++tot]=Edge(u,head[v],0,-cap); head[v]=tot;
}
 
bool BFS()	
{
	for ( int i=1; i<=n; i++ )
		dis[i]=INF,vis[i]=0;
	queue<int> q; q.push( S ); dis[S]=0; nw[S]=head[S]; vis[S]=1;
	while ( !q.empty() )
	{
		int u=q.front(); q.pop(); vis[u]=0;
		for ( int i=head[u]; i; i=e[i].nxt )
		{
			int v=e[i].to;
			if ( e[i].flow && dis[v]>dis[u]+e[i].cap )
			{
				nw[v]=head[v]; dis[v]=dis[u]+e[i].cap;
				if ( !vis[v] ) vis[v]=1,q.push(v);
			}
		}
	}
	return dis[T]!=INF;
}
 
int DFS( int u,int sum )		
{
	if ( u==T ) return sum;
	vis[u]=1; int res=0;
	for ( int i=nw[u]; i && sum; i=e[i].nxt )
	{
		nw[u]=i; int v=e[i].to;
		if ( !vis[v] && e[i].flow && (dis[v]==dis[u]+e[i].cap) )
		{
			int tmp=DFS( v,min(sum,e[i].flow) );
			if ( tmp )
			{
				e[i].flow-=tmp; e[i^1].flow+=tmp;
				res+=tmp; sum-=tmp;	mncost+=e[i].cap*tmp;
			}
		}
	}
	vis[u]=0; return res;
}
 
int main()
{
	n=read(); m=read(); S=1; T=n;
	for ( int i=1,u,v,f,c; i<=m; i++ )
		u=read(),v=read(),f=read(),c=read(),Add(u,v,f,c);
 
	while ( BFS() ) mxflow+=DFS(S,INF);
 
	printf( "%d %d\n",mxflow,mncost );
 
	return 0;
}
类Dinic(vector)
//Author:RingweEH
const int N=410,M=15010,INF=0x3f3f3f3f;
struct Edge
{
	int to,flow,cost;
	Edge ( int _to=0,int _flow=0,int _cost=0 ) :
	 	to(_to),flow(_flow),cost(_cost) {}
};
vector<Edge> e;
vector<int> g[N];
int n,m,S,T,dis[N],mxflow,mncost,nw[N];
bool vis[N];

void Add( int u,int v,int fl,int cost )
{
	e.push_back(Edge(v,fl,cost));
	e.push_back(Edge(u,0,-cost));
	int siz=e.size(); g[u].push_back(siz-2); g[v].push_back(siz-1);
}
 
bool BFS()	
{
	for ( int i=1; i<=n; i++ )
		dis[i]=INF,vis[i]=0,nw[i]=0;
	queue<int> q; q.push( S ); dis[S]=0; vis[S]=1;
	while ( !q.empty() )
	{
		int u=q.front(); q.pop(); vis[u]=0;
		for ( int ei=0; ei<g[u].size(); ei++ )
		{
			int i=g[u][ei]; int v=e[i].to;
			if ( e[i].flow && dis[v]>dis[u]+e[i].cost )
			{
				dis[v]=dis[u]+e[i].cost;
				if ( !vis[v] ) vis[v]=1,q.push(v);
			}
		}
	}
	return dis[T]!=INF;
}
 
int DFS( int u,int sum )		
{
	if ( u==T ) return sum;
	vis[u]=1; int res=0;
	for ( int ei=nw[u]; ei<g[u].size() && sum; ei++ )
	{
		int i=g[u][ei]; nw[u]=i; int v=e[i].to;
		if ( !vis[v] && e[i].flow && (dis[v]==dis[u]+e[i].cost) )
		{
			int tmp=DFS( v,min(sum,e[i].flow) );
			if ( tmp )
			{
				e[i].flow-=tmp; e[i^1].flow+=tmp;
				res+=tmp; sum-=tmp;	mncost+=e[i].cost*tmp;
			}
		}
	}
	vis[u]=0; return res;
}
 
int main()
{
	n=read(); m=read(); S=1; T=n;
	for ( int i=1,u,v,f,c; i<=m; i++ )
		u=read(),v=read(),f=read(),c=read(),Add(u,v,f,c);
 
	while ( BFS() ) mxflow+=DFS(S,INF);
 
	printf( "%d %d\n",mxflow,mncost );
 
	return 0;
}

上下界网络流

无源汇上下界可行流
//Author:RingweEH
const int N=210,M=11000,INF=0x3f3f3f3f;
struct Edge
{
    int to,nxt,flow;
}e[M<<1];
int n,m,S,T,tot=1,nw[N],head[N],low[M];
int mxflow,dis[N],c[N];
 
void Add( int u,int v,int w )
{
    e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].flow=w;
    e[++tot].to=u; e[tot].nxt=head[v]; head[v]=tot; e[tot].flow=0;
}
 
bool BFS()   
{
    for ( int i=1; i<=n+2; i++ )
        dis[i]=INF,nw[i]=head[i];
    queue<int> q; q.push( S ); dis[S]=0;
    while ( !q.empty() )
    {
        int u=q.front(); q.pop();
        for ( int i=head[u]; i; i=e[i].nxt )
        {
            int v=e[i].to;
            if ( e[i].flow>0 && dis[v]==INF )
            {
                q.push( v ); dis[v]=dis[u]+1;
                if ( v==T ) return 1;
            }
        }
    }
    return 0;
}
 
int DFS( int u,int sum )   
{
    if ( u==T ) return sum;
    int res=0;
    for ( int i=nw[u]; i && sum; i=e[i].nxt )
    {
        nw[u]=i; int v=e[i].to;
        if ( e[i].flow>0 && (dis[v]==dis[u]+1) )
        {
            int tmp=DFS( v,min(sum,e[i].flow) );
            if ( tmp==0 ) dis[v]=INF; 
            e[i].flow-=tmp; e[i^1].flow+=tmp;
            res+=tmp; sum-=tmp;  
        }
    }
    return res;
}
 
int main()
{
    n=read(); m=read(); S=n+1; T=S+1;
    for ( int i=1; i<=m; i++ )
    {
        int u=read(),v=read(),lower=read(),upper=read();
        Add( u,v,upper-lower ); c[v]+=lower; c[u]-=lower;
        low[i]=lower;
    }

    int Sum=0;
    for ( int i=1; i<=n; i++ )
    {
        if ( c[i]>0 ) Add( S,i,c[i] ),Sum+=c[i];
        if ( c[i]<0 ) Add( i,T,-c[i] );
    }
 
    while ( BFS() ) mxflow+=DFS(S,INF);

    if ( mxflow==Sum )
    {
        printf( "YES\n" );
        for ( int i=3,j=1; j<=m; i+=2,j++ )
            printf( "%lld\n",e[i].flow+low[j] );
    }
    else printf( "NO\n" );
 
    return 0;
}
有源汇上下界最大流
//Author:RingweEH
const int N=210,M=1e4+N*2,INF=0x3f3f3f3f;
struct Edge
{
    int to,nxt,flow;
}e[M<<1];
int n,m,S,T,tot=1,nw[N],head[N],low[M];
int mxflow,dis[N],c[N];
 
void Add( int u,int v,int w )
{
    e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].flow=w;
    e[++tot].to=u; e[tot].nxt=head[v]; head[v]=tot; e[tot].flow=0;
}
 
bool BFS()   
{
    for ( int i=1; i<=n+2; i++ )
        dis[i]=INF,nw[i]=head[i];
    queue<int> q; q.push( S ); dis[S]=0;
    while ( !q.empty() )
    {
        int u=q.front(); q.pop();
        for ( int i=head[u]; i; i=e[i].nxt )
        {
            int v=e[i].to;
            if ( e[i].flow>0 && dis[v]==INF )
            {
                q.push( v ); dis[v]=dis[u]+1;
                if ( v==T ) return 1;
            }
        }
    }
    return 0;
}
 
int DFS( int u,int sum )   
{
    if ( u==T ) return sum;
    int res=0;
    for ( int i=nw[u]; i && sum; i=e[i].nxt )
    {
        nw[u]=i; int v=e[i].to;
        if ( e[i].flow>0 && (dis[v]==dis[u]+1) )
        {
            int tmp=DFS( v,min(sum,e[i].flow) );
            if ( tmp==0 ) dis[v]=INF; 
            e[i].flow-=tmp; e[i^1].flow+=tmp;
            res+=tmp; sum-=tmp;  
        }
    }
    return res;
}
 
int main()
{
    n=read(); m=read(); int s=read(),t=read(); S=n+1,T=S+1;
    for ( int i=1; i<=m; i++ )
    {
        int u=read(),v=read(),lower=read(),upper=read(); low[i]=lower;
        Add( u,v,upper-lower ); c[v]+=lower; c[u]-=lower;
    }

    int Sum=0; Add( t,s,INF );
    for ( int i=1; i<=n; i++ )
    {
        if ( c[i]>0 ) Add( S,i,c[i] ),Sum+=c[i];
        if ( c[i]<0 ) Add( i,T,-c[i] );
    }
    while ( BFS() ) mxflow+=DFS(S,INF);
    if ( mxflow!=Sum ) { printf( "please go home to sleep" ); return 0; }
    S=s; T=t; mxflow=0;
    while ( BFS() ) mxflow+=DFS(S,INF);
    printf( "%d\n",mxflow );
 
    return 0;
}
有源汇上下界最小流
//Author:RingweEH
const int N=5e4+10,M=125010+N*2;
const ll INF=1e16;
struct Edge
{
    int to,nxt; ll flow;
}e[M<<1];
int n,m,S,T,tot=1,nw[N],head[N],low[M];
ll mxflow,dis[N],c[N];
 
void Add( int u,int v,ll w )
{
    e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; e[tot].flow=w;
    e[++tot].to=u; e[tot].nxt=head[v]; head[v]=tot; e[tot].flow=0;
}
 
bool BFS()   
{
    for ( int i=1; i<=n+2; i++ )
        dis[i]=INF,nw[i]=head[i];
    queue<int> q; q.push( S ); dis[S]=0;
    while ( !q.empty() )
    {
        int u=q.front(); q.pop();
        for ( int i=head[u]; i; i=e[i].nxt )
        {
            int v=e[i].to;
            if ( e[i].flow>0 && dis[v]==INF )
            {
                q.push( v ); dis[v]=dis[u]+1;
                if ( v==T ) return 1;
            }
        }
    }
    return 0;
}
 
ll DFS( int u,ll sum )   
{
    if ( u==T ) return sum;
    ll res=0;
    for ( int i=nw[u]; i && sum; i=e[i].nxt )
    {
        nw[u]=i; int v=e[i].to;
        if ( e[i].flow>0 && (dis[v]==dis[u]+1) )
        {
            ll tmp=DFS( v,min(sum,e[i].flow) );
            if ( tmp==0 ) dis[v]=INF; 
            e[i].flow-=tmp; e[i^1].flow+=tmp;
            res+=tmp; sum-=tmp;  
        }
    }
    return res;
}
 
int main()
{
    n=read(); m=read(); int s=read(),t=read(); S=n+1,T=S+1;
    for ( int i=1; i<=m; i++ )
    {
        int u=read(),v=read(); ll lower=read(),upper=read(); 
        low[i]=lower; Add( u,v,upper-lower ); c[v]+=lower; c[u]-=lower;
    }

    int Sum=0;
    for ( int i=1; i<=n; i++ )
    {
        if ( c[i]>0 ) Add( S,i,c[i] ),Sum+=c[i];
        if ( c[i]<0 ) Add( i,T,-c[i] );
    }
    Add( t,s,INF );
    while ( BFS() ) mxflow+=DFS(S,INF);
    if ( mxflow!=Sum ) { printf( "please go home to sleep" ); return 0; }
    mxflow=e[tot].flow;
    S=t; T=s; e[tot].flow=e[tot^1].flow=0;
    while ( BFS() ) mxflow-=DFS(S,INF);
    printf( "%lld\n",mxflow );

    return 0;
}

生成树

最小树形图——朱刘算法
//Author: RingweEH
//P4716 【模板】最小树形图
const int N=110,M=1e4+10,inf=0x3f3f3f3f;
struct edge
{
    int u,v; ll val;
}e[M];
int n,m,rt,cnt_cyc,fa[N],incyc_id[N],f[N],min_pre[N];
ll ans=0;

int ZhuLiu()
{
    while ( 1 )
    {
        cnt_cyc=0;
        for ( int i=1; i<=n; i++ )
            incyc_id[i]=f[i]=0,min_pre[i]=inf;
        //---------------------init----------------------
        for ( int i=1; i<=m; i++ )
            if ( e[i].u!=e[i].v && e[i].val<min_pre[e[i].v] )
                fa[e[i].v]=e[i].u,min_pre[e[i].v]=e[i].val;
        //--------------找每个点的最小入边---------------
        int now=min_pre[rt]=0;
        for ( int i=1; i<=n; i++ )
        {
            if ( min_pre[i]==inf ) return 0;    //孤立点特判
            ans+=min_pre[i];        //不管如何先把边权加进去就好了
            for ( now=i; now!=rt && f[now]!=i && !incyc_id[now]; now=fa[now] )
                f[now]=i;   //从i不断往选定的入边跳,途中不能往其他已经判定的环里面跳
            if ( now!=rt && !incyc_id[now] )    
            //看上面循环的判断条件,只满足了 f[now]==i ,也就是形成了环
            {
                incyc_id[now]=++cnt_cyc;
                for ( int v=fa[now]; v!=now; v=fa[v] )
                    incyc_id[v]=cnt_cyc;
            }
        }
        if ( !cnt_cyc ) return 1;
        //-----------------------找环----------------------
        for ( int i=1; i<=n; i++ )  //给不在环中的点也赋一个标号,方便判断
            if ( !incyc_id[i] ) incyc_id[i]=++cnt_cyc; 
        for ( int i=1; i<=m; i++ )
        {
            int las=min_pre[e[i].v];    //e[i].v的最小入边权
            e[i].u=incyc_id[e[i].u]; e[i].v=incyc_id[e[i].v];   //缩成同一个点,也就是环编号
            if ( e[i].u!=e[i].v )  e[i].val-=las;   //如果不在同一个环里面就修改边权
        }
        n=cnt_cyc; rt=incyc_id[rt]; //缩点完成后的点数就是环的个数,并更新根节点编号。
    }
}

int main()
{
    n=read(); m=read(); rt=read();
    for ( int i=1; i<=m; i++ )
        e[i]=(edge){read(),read(),read()};
    
    if ( ZhuLiu() ) printf( "%lld",ans );
    else printf( "-1\n" );
    return 0;
}

其他

DSU on Tree
//Author: RingweEH
//CF600E Lomsat gelral
#include <cstdio>
#include <cstring>
#include <algorithm>
#define ll long long
#define db double
using namespace std;
int min( int a,int b ) { return a<b ? a : b; }
int max( int a,int b ) { return a>b ? a : b; }
void bmax( int &a,int b ) { a=(a>b) ? a : b; }
void bmin( int &a,int b ) { a=(a<b) ? a : b; }
const int L=1<<20;
char buf[L],*p1,*p2;
#define getchar() (p1==p2?(p2=buf+fread(p1=buf,1,L,stdin),p1==p2?EOF:*p1++):*p1++)
int read()
{
    int x=0,w=1; char ch=getchar();
    while ( ch>'9' || ch<'0' ) { if ( ch=='-' ) w=-1; ch=getchar(); }
    while ( ch<='9' && ch>='0' ) x=x*10+ch-'0',ch=getchar();
    return x*w;
}

const int N=1e5+10;
struct Node { int to,nxt; }e[N<<1];
int fa[N],siz[N],wson[N],head[N],tot,cnt[N],col[N],con,n;
ll s[N],ans[N],sum,mx;

void Adde( int u,int v ) { e[++tot].to=v; e[tot].nxt=head[u]; head[u]=tot; }
void DFS1( int u )
{
	siz[u]=1;
	for ( int i=head[u]; i; i=e[i].nxt )
	{
		int v=e[i].to;
		if ( v==fa[u] ) continue;
		fa[v]=u; DFS1(v); siz[u]+=siz[v];
		if ( siz[v]>=siz[wson[u]] ) wson[u]=v;
	}
}
void Add( int u,int val )
{
	s[col[u]]+=val;
	if ( mx<s[col[u]] ) mx=s[col[u]],sum=col[u];
	else if ( mx==s[col[u]] ) sum+=col[u];
	for ( int i=head[u]; i; i=e[i].nxt )
	{
		int v=e[i].to;
		if ( v==fa[u] || v==con ) continue;
		Add(v,val);
	}
}
void DSU( int u,bool fl )
{
	for ( int i=head[u]; i; i=e[i].nxt )
	{
		int v=e[i].to;
		if ( (v^fa[u]) && (v^wson[u]) ) DSU(v,1);
	}
	if ( wson[u] ) DSU(wson[u],0),con=wson[u];
	Add(u,1); con=0; ans[u]=sum;
	if ( fl ) Add(u,-1),sum=mx=0;
}

int main()
{
//freopen( "exam.in","r",stdin );

	n=read();
	for ( int i=1; i<=n; i++ ) col[i]=read();
	for ( int i=1,u,v; i<n; i++ ) u=read(),v=read(),Adde(u,v),Adde(v,u);

	DFS1(1); DSU(1,0);
	
	for ( int i=1; i<=n; i++ ) printf("%lld\n",ans[i] );

	return 0;
}
posted @ 2020-11-12 13:39  MontesquieuE  阅读(21)  评论(0编辑  收藏  举报