[P2173][ZJOI2012]网络(LCT)

颜色数很少,可以每种颜色用一个lct维护。

更改节点值就把每个lct的改节点都转到根改一下。

更改边的颜色时,先枚举颜色,若每个lct中x和y节点都不连通,则No such edge.;如果之前的颜色和新的颜色相同,直接Success.;每个节点维护一下它连的边的数量s,s只在link和cut操作时会修改,如果在新颜色中x或y的s已经为2,则Error 1.;

split判断x和y是否已连通,连通则Error 2.;前面几种情况都不是则断旧颜色边,连新颜色边,输出Success.。

查询路径上最大点权也用split判断是否存在路径。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=10010;
struct node{
	int l,r,fa,x,m,s;
	bool rev;
}tree[10][N];
int n,m,c1,k,q[N];
inline int read(){
	int x=0,f=0;
	char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return f?-x:x;
}
inline void update(int c,int p){
	tree[c][p].m=max(tree[c][tree[c][p].l].m,tree[c][tree[c][p].r].m);
	tree[c][p].m=max(tree[c][p].m,tree[c][p].x);
}
inline void new1(int c,int p){
	swap(tree[c][p].l,tree[c][p].r);
	tree[c][p].rev=!tree[c][p].rev;
}
inline void pushdown(int c,int p){
	if(tree[c][p].rev){
		new1(c,tree[c][p].l);new1(c,tree[c][p].r);
		tree[c][p].rev=false;
	}
}
inline bool nroot(int c,int p){
	return tree[c][tree[c][p].fa].l==p||tree[c][tree[c][p].fa].r==p;
}
inline void left_rotate(int c,int p){
	int q=tree[c][p].fa,r=tree[c][q].fa;
	tree[c][q].r=tree[c][p].l;
	if(tree[c][p].l)tree[c][tree[c][p].l].fa=q;
	if(nroot(c,q)){
		if(tree[c][r].l==q)tree[c][r].l=p;
		else tree[c][r].r=p;
	}
	tree[c][q].fa=p;tree[c][p].l=q;tree[c][p].fa=r;
	update(c,q);update(c,p);
}
inline void right_rotate(int c,int p){
	int q=tree[c][p].fa,r=tree[c][q].fa;
	tree[c][q].l=tree[c][p].r;
	if(tree[c][p].r)tree[c][tree[c][p].r].fa=q;
	if(nroot(c,q)){
		if(tree[c][r].l==q)tree[c][r].l=p;
		else tree[c][r].r=p;
	}
	tree[c][q].fa=p;tree[c][p].r=q;tree[c][p].fa=r;
	update(c,q);update(c,p);
}
inline bool getlr(int c,int p){
	return tree[c][tree[c][p].fa].l==p;
}
inline void rotate(int c,int p){
	if(getlr(c,p))right_rotate(c,p);
	else left_rotate(c,p);
}
inline void splay(int c,int p){
	int cnt=0;q[++cnt]=p;
	for(int i=p;nroot(c,i);i=tree[c][i].fa)q[++cnt]=tree[c][i].fa;
	while(cnt)pushdown(c,q[cnt--]);
	while(nroot(c,p)){
		int q=tree[c][p].fa;
		if(nroot(c,q)){
			if(getlr(c,p)==getlr(c,q))rotate(c,q);
			else rotate(c,p);
		}rotate(c,p);
	}
}
inline void access(int c,int p){
	for(int x=0;p;x=p,p=tree[c][p].fa){splay(c,p);tree[c][p].r=x;update(c,p);}
}
inline void makeroot(int c,int p){
	access(c,p);splay(c,p);new1(c,p);
}
inline void link(int c,int x,int y){
	makeroot(c,x);tree[c][x].fa=y;tree[c][y].s++;tree[c][x].s++;
}
inline int findroot(int c,int x){
	access(c,x);splay(c,x);
	while(tree[c][x].l){pushdown(c,x);x=tree[c][x].l;}
	splay(c,x);
	return x;
}
inline bool split(int c,int x,int y){
	makeroot(c,y);
	if(findroot(c,x)!=y)return false;
	return true;
}
inline void cut(int c,int x,int y){
	makeroot(c,x);tree[c][x].r=tree[c][y].fa=0;update(c,x);
	tree[c][x].s--;tree[c][y].s--;
}
inline void change(int x,int w){
	for(int i=0;i<c1;i++){splay(i,x);tree[i][x].x=w;update(i,x);}
}
inline bool check(int c,int x,int y){
	makeroot(c,x);access(c,y);splay(c,x);
	return tree[c][y].fa==x&&!tree[c][y].l;
}
int main(){
	n=read();m=read();c1=read();k=read();
	for(int x,i=1;i<=n;i++){
		x=read();
		for(int j=0;j<c1;j++){
			tree[j][i].l=tree[j][i].r=tree[j][i].fa=0;
			tree[j][i].x=tree[j][i].m=x;
			tree[j][i].s=0;
			tree[j][i].rev=false;
		}
	}
	for(int x,y,c,i=1;i<=m;i++){
		x=read();y=read();c=read();
		link(c,x,y);
	}
	for(int q,i=1;i<=k;i++){
		q=read();
		if(!q){
			int x=read(),w=read();
			change(x,w);
		}else if(q==1){
			int u=read(),v=read(),w=read(),pre=-1;
			if(u==v){printf("Success.\n");continue;}
			for(int j=0;j<c1;j++)if(check(j,u,v)){pre=j;break;}
			if(pre==-1){printf("No such edge.\n");continue;}
			if(pre==w){printf("Success.\n");continue;}
			if(tree[w][u].s==2||tree[w][v].s==2){printf("Error 1.\n");continue;}
			if(split(w,u,v)){printf("Error 2.\n");continue;}
			cut(pre,u,v);link(w,u,v);printf("Success.\n");
		}else{
			int c=read(),u=read(),v=read();
			if(!split(c,u,v))printf("-1\n");
			else printf("%d\n",tree[c][v].m);
		}
	}
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值