3883. 【NOIP2014模拟】线段树

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; 
}

猜你喜欢

转载自blog.csdn.net/zsjzliziyang/article/details/104641140
今日推荐