顔色數很少,可以每種顔色用一個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;
}