【題解】[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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章