【题解】[ZJOI2012]网络

[ZJOI2012]网络

\(\text{Solution:}\)

很明显对着颜色分别维护 \(LCT,\) 想法在看到颜色的数据范围后也得到了证实。

那么,怎么维护?

有显然的断边连边操作,还要维护一下链上最大值,直接上 \(LCT.\)

但是题目中的特殊情况很难判断,提出一些小坑:

有可能删掉和加上的边是同一种颜色,所以要特判,否则先判就会测成 Error 1.

如果用 set 去维护每个点连出去的边的话,会发生一些奇怪的错误,可能是因为判断重复的时候有编号一样但颜色不一样的边?

这个地方用 map 处理会更好一些,但要注意尽量用 map.count 访问,因为有时候用下标访问会新建一个元素导致判空错误。

#include<bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f ;
const int N=5e5+10;
int n,m,v[N],st[N],C,k,CC[N][10];
int mx[N],ch[N][2],f[N],rev[N];
struct Node{
	int u,v;
	bool operator<(const Node&B)const{
		return u==B.u?v<B.v:u<B.u;
	}
	Node(int xx=0,int yy=0){u=xx,v=yy;}
};
map<Node,int>mp;
inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}
inline void pushup(int x){mx[x]=Max(Max(mx[ch[x][0]],mx[ch[x][1]]),v[x]);}
inline void pushr(int x){
	rev[x]^=1;
	int t=ch[x][0];
	ch[x][0]=ch[x][1];
	ch[x][1]=t;
}
inline bool nroot(int x){return ch[f[x]][0]==x||ch[f[x]][1]==x;}
inline void rotate(int x){
	int y=f[x],z=f[y],k=(ch[y][1]==x),w=ch[x][k^1];
	if(nroot(y))ch[z][ch[z][1]==y]=x;ch[x][k^1]=y;ch[y][k]=w;
	if(w)f[w]=y;f[y]=x;f[x]=z;pushup(y);pushup(x);
}
inline void pushdown(int x){
	if(rev[x]){
		if(ch[x][0])pushr(ch[x][0]);
		if(ch[x][1])pushr(ch[x][1]);
		rev[x]^=1;
	}
}
inline void splay(int x){
	int y=x,z=0;
	st[++z]=y;
	while(nroot(y))st[++z]=y=f[y];
	while(z)pushdown(st[z--]);
	while(nroot(x)){
		y=f[x];z=f[y];
		if(nroot(y))rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y);
		rotate(x);
	}
	pushup(x);
}
inline void access(int x){
	for(int y=0;x;y=x,x=f[x]){
		splay(x),ch[x][1]=y;pushup(x);
	}
}
inline void makeroot(int x){
	access(x);splay(x);pushr(x);
}
int findroot(int x){
	access(x);splay(x);
	while(ch[x][0])pushdown(x),x=ch[x][0];
	splay(x);return x;
}
inline void split(int x,int y){
	makeroot(x);access(y);splay(y);
}
inline void link(int x,int y){
	makeroot(x);
	if(findroot(y)!=x)f[x]=y;
}
inline void cut(int x,int y){
	makeroot(x);
	if(findroot(y)==x&&f[y]==x&&!ch[y][0]){
		f[y]=ch[x][1]=0;
		pushup(x);
	}
}
int main(){
	scanf("%d%d%d%d",&n,&m,&C,&k);
	for(int i=1;i<=n;++i)scanf("%d",&v[i]);
	for(int i=1;i<=n;++i)
		for(int j=0;j<C;++j)
			v[i+j*n]=v[i];
	for(int i=1;i<=m;++i){
		int u,v,c;
		scanf("%d%d%d",&u,&v,&c);
		mp[Node(u,v)]=c;mp[Node(v,u)]=c;
		CC[u][c]++;CC[v][c]++;
		link(u+c*n,v+c*n);
	}
	for(int jjj=1;jjj<=k;++jjj){
		int opt,x,y,z;
		scanf("%d%d%d",&opt,&x,&y);
		if(opt==0){
			for(int i=0;i<C;++i)splay(x+i*n),v[x+i*n]=y;
			continue;
		}
		if(opt==1){
			int u=x,v=y;
			scanf("%d",&z);
			Node edge1=Node(x,y);
			Node edge2=Node(y,x);
			if(!mp.count(edge1)||!mp.count(edge2)){
				puts("No such edge.");
				continue;
			}
			int Col=mp[edge1];
			if(Col==z){
				puts("Success.");
				continue;
			}
			if(CC[u][z]==2){
				puts("Error 1.");
				continue;
			}
			if(CC[v][z]==2){
				puts("Error 1.");
				continue;
			}
			makeroot(u+z*n);
			int fv=findroot(v+z*n);
			if(fv==u+z*n){
				puts("Error 2.");
				continue;
			}
			mp.erase(edge1);
			mp.erase(edge2);
			mp[edge1]=z;
			mp[edge2]=z;
			cut(u+Col*n,v+Col*n);
			CC[u][Col]--;
			CC[u][z]++;
			link(u+z*n,v+z*n);
			CC[v][Col]--;
			CC[v][z]++;
			puts("Success.");
			continue;
		}
		if(opt==2){
			scanf("%d",&z);
			int u=y+x*n,v=z+x*n;
			makeroot(v);
			int fv=findroot(v);
			int fu=findroot(u);
			if(fu!=fv){
				puts("-1");
				continue;
			}
			split(u,v);
			printf("%d\n",mx[v]);
		}
	}
	return 0;
}
posted @ 2021-07-26 17:26  Refined_heart  阅读(30)  评论(0编辑  收藏  举报