Description
给定一个n个点n-1条边的无向连通图(一棵树),并对图中的边进行m次染色操作。
每次染色操作给定2个点u、v和一种颜色c,并将图中u,v之间的最短路上的边都染成这种颜色。
询问的是最终图中每条边的颜色。(若未被染色则视为颜色0即无色)
Input
第1行:2个整数n,m
第2到第n行:第i行表示i号点的父节点fi
接下来m行:每行3个整数ui,vi,ci分别表示给定的节点u、v和颜色c。
Output
共n-1行:第i行输出第i+1个点与其父节点之间边的颜色。
Sample Input
5 3 1 1 1 2 1 2 1 1 2 2 4 5 1
Sample Output
1 0 1 1
Data Constraint
对于10%的数据,n,m<=100
对于30%的数据,n,m<=5000
对于60%的数据,n,m<=100000
对于100%的数据,n,m<=500000,0<ci<=m
Solution
通过从后往前更新,那么越后面的越优先覆盖,覆盖完的就不用再更新,那么很容易想到用并查集合并到一起就可以了。
Code
#include<cstdio>
#include<algorithm>
#define I int
#define F(i,a,b) for(register int i=a;i<=b;++i)
#define Fd(i,a,b) for(register int i=a;i>=b;--i)
#define N 500004
using namespace std;
I n,m,f[N],x[N],y[N],z[N],g[N],a[N],l[N],nx[N<<1],t[N<<1],d[N],q[N],bz[N],tot;
I R(I &x){
x=0;char ch=getchar();for(;ch<'0'||ch>'9';ch=getchar()) ;
for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
}
inline I get(I x){return g[x]==x?x:g[x]=get(g[x]);}
inline void wk(I x,I y,I z){
x=get(x),y=get(y);
while(x!=y){
if(d[x]<d[y]) x^=y,y^=x,x^=y;
a[x]=z,x=get(g[x]=f[x]);
}
}
inline void add(I x,I y){t[++tot]=y,nx[tot]=l[x],l[x]=tot;}
I main(){
R(n),R(m);
F(i,2,n) R(f[i]),add(i,f[i]),add(f[i],i);
I j=1;q[1]=d[1]=1;bz[1]=1;
F(i,1,j){for(I x=q[i],k=l[g[x]=x];k;k=nx[k]) if(!bz[t[k]]){bz[q[++j]=t[k]]=1,d[t[k]]=d[x]+1;}}
F(i,1,m) R(x[i]),R(y[i]),R(z[i]);
Fd(i,m,1) wk(x[i],y[i],z[i]);
F(i,2,n) printf("%d\n",a[i]);
return 0;
}