【模板】图论
二分图
二分图最大匹配(匈牙利)
//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;
}
大地也该是从一片类似的光明中冒出来的。