( ext{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
",mx[v]);
}
}
return 0;
}