NC20506. [ZJOI2012]网络
描述
有一个无向图G,每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:
对于任意节点连出去的边中,相同颜色的边不超过两条。
图中不存在同色的环,同色的环指相同颜色的边构成的环。
在这个图上,你要支持以下三种操作:
修改一个节点的权值。
修改一条边的颜色。
查询由颜色c的边构成的图中,所有可能在节点u到节点v之间的简单路径上的节点的权值的最大值。
输入描述
输入文件network.in的第一行包含四个正整数N, M, C, K,其中N为节点个数,M为边数,C为边的颜色数,K为操作数。
接下来N行,每行一个正整数vi,为节点i的权值。
之后M行,每行三个正整数u, v, w,为一条连接节点u和节点v的边,颜色为w。满足1 ≤ u, v ≤ N,0 ≤ w < C,保证u ≠ v,且任意两个节点之间最多存在一条边(无论颜色)。
最后K行,每行表示一个操作。每行的第一个整数k表示操作类型。
k = 0为修改节点权值操作,之后两个正整数x和y,表示将节点x的权值vx修改为y。
k = 1为修改边的颜色操作,之后三个正整数u, v和w,表示将连接节点u和节点v的边的颜色修改为颜色w。满足0 ≤ w < C。
k = 2为查询操作,之后三个正整数c, u和v,表示查询所有可能在节点u到节点v之间的由颜色c构成的简单路径上的节点的权值的最大值。如果不存在u和v之间不存在由颜色c构成的路径,那么输出“-1”。
输出描述
输出文件network.out包含若干行,每行输出一个对应的信息。
对于修改节点权值操作,不需要输出信息。
对于修改边的颜色操作,按以下几类输出:
a) 若不存在连接节点u和节点v的边,输出“No such edge.”。
b) 若修改后不满足条件1,不修改边的颜色,并输出“Error 1.”。
c) 若修改后不满足条件2,不修改边的颜色,并输出“Error 2.”。
d) 其他情况,成功修改边的颜色,并输出“Success.”。
输出满足条件的第一条信息即可,即若同时满足b和c,则只需要输出“Error 1.”。
对于查询操作,直接输出一个整数。
示例1
输入:
4 5 2 7 1 2 3 4 1 2 0 1 3 1 2 3 0 2 4 1 3 4 0 2 0 1 4 1 1 2 1 1 4 3 1 2 0 1 4 1 2 3 1 0 2 5 2 1 1 4
输出:
4 Success. Error 2. -1 Error 1. 5
说明:
颜色0为实线的边,颜色1为虚线的边,
由颜色0构成的从节点1到节点4的路径有 ,故。
将连接节点1和节点2的边修改为颜色1,修改成功,输出 Success.
将连接节点4和节点3的边修改为颜色1,由于修改后会使得存在由颜色1构成的环( 1–2–4–3–1 ),不满足条件 2,故不修改,并输Error 2。
不存在颜色0构成的从节点1到节点4的边,输出-1。
将连接节点2和节点3的边修改为颜色1,由于修改后节点 22 的连出去的颜色为1的边有3条,故不满足条件 1,故不修改,并输出Error 1. 。
将节点2的权值修改为5。
由颜色1构成的从节点1到节点4的路径有 ,故。
C++14(g++5.4) 解法, 执行用时: 677ms, 内存消耗: 5752K, 提交时间: 2019-04-16 21:09:39
#include<bits/stdc++.h> using namespace std; const int N=10005; int n,m,t,k,opt,x,y,z,root,c; int zhan[N],val[N],fa[10][N],ans[10][N],tag[10][N],d[10][N],ch[10][N][2]; /*char buf[1<<21],*p1=buf,*p2=buf; inline int gc() { return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++; }*/ #define gc getchar inline int read() { int ret=0,f=0; char c=gc(); while(!isdigit(c)) { if(c=='-')f=1; c=gc(); } while(isdigit(c)) { ret=ret*10+c-48; c=gc(); } if(f)return -ret; return ret; } bool chk(int c,int u) { return ch[c][fa[c][u]][1]==u; } bool pd(int c,int u) { return ch[c][fa[c][u]][0]==u||ch[c][fa[c][u]][1]==u; } void pushup(int c,int x) { ans[c][x]=max(ans[c][ch[c][x][0]],max(ans[c][ch[c][x][1]],val[x])); } void pushdown(int c,int x) { int l=ch[c][x][0],r=ch[c][x][1]; if(tag[c][x]) { if(l) { swap(ch[c][l][0],ch[c][l][1]); tag[c][l]^=1; } if(r) { swap(ch[c][r][0],ch[c][r][1]); tag[c][r]^=1; } tag[c][x]=0; } } void Zhuan(int c,int x) { int y=fa[c][x],z=fa[c][y],k=chk(c,x),w=ch[c][x][k^1]; if(pd(c,y))ch[c][z][chk(c,y)]=x; ch[c][x][k^1]=y,ch[c][y][k]=w; if(w)fa[c][w]=y;fa[c][y]=x,fa[c][x]=z; pushup(c,y);pushup(c,x); } void splay(int c,int x) { int y=x,top=0; zhan[++top]=y; while(pd(c,y))zhan[++top]=y=fa[c][y]; while(top)pushdown(c,zhan[top--]); while(pd(c,x)) { y=fa[c][x]; if(pd(c,y)) { if(chk(c,x)==chk(c,y))Zhuan(c,y); else Zhuan(c,x); } Zhuan(c,x); } pushup(c,x); return; } void access(int c,int x) { for(int y=0;x;y=x,x=fa[c][x]) { splay(c,x); ch[c][x][1]=y; pushup(c,x); } } void makeroot(int c,int x) { access(c,x);splay(c,x); swap(ch[c][x][0],ch[c][x][1]); tag[c][x]^=1; } int findroot(int c,int x) { access(c,x);splay(c,x); while(ch[c][x][0])x=ch[c][x][0]; splay(c,x); return x; } void split(int c,int x,int y) { makeroot(c,x); access(c,y);splay(c,y); } void link(int c,int x,int y) { d[c][x]++; d[c][y]++; makeroot(c,x); fa[c][x]=y; } void cut(int c,int x,int y) { d[c][x]--; d[c][y]--; split(c,x,y); fa[c][x]=ch[c][y][0]=0; } void dian(int c) { int x=read(),y=read(); for(int i=0;i<c;i++) { access(i,x); splay(i,x); } val[x]=y; for(int i=0;i<c;i++)pushup(i,x); } void bian(int c) { int u=read(),v=read(),w=read(); for(int i=0;i<c;i++) if(findroot(i,u)==findroot(i,v)) { split(i,u,v); if(ch[i][v][0]!=u||ch[i][u][1])continue; if(i==w) { puts("Success."); return; } if((d[w][u]==2)||(d[w][v]==2)) { puts("Error 1."); return; } else if(findroot(w,u)==findroot(w,v)) { puts("Error 2."); return; } else{ cut(i,u,v);link(w,u,v); puts("Success."); return; } } puts("No such edge."); } void query() { int c=read(),u=read(),v=read(); if(findroot(c,u)!=findroot(c,v)) { puts("-1"); return; } split(c,u,v); printf("%d\n",ans[c][v]); } int main() { n=read();m=read();c=read();k=read(); for(int i=1;i<=n;i++)val[i]=read(); while(m--) { int x=read(),y=read(),z=read(); link(z,x,y); } while(k--) { int opt=read(); if(opt==0)dian(c); else if(opt==1)bian(c); else if(opt==2)query(); } return 0; }
C++11(clang++ 3.9) 解法, 执行用时: 515ms, 内存消耗: 9080K, 提交时间: 2019-03-16 12:23:17
#include<bits/stdc++.h> using namespace std; int read(){ int x=0,f=1;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 x*f; } const int N=10005, M=100005; int n,m,C,K; int v[N],stk[N]; struct Edge{ int u,v; bool operator <(Edge x)const{ if (x.u!=u) return x.u>u; else return x.v>v; } }; map<Edge,int>E; struct LinkCutTree{ int pre[N],son[N][2],Max[N],cnt[N]; bool rev[N]; bool isroot(int x){ return son[pre[x]][0]!=x && son[pre[x]][1]!=x; } void up(int x){ Max[x]=v[x]; int l=son[x][0],r=son[x][1]; Max[x]=max(Max[l],max(Max[x],Max[r])); } void down(int x){ if (rev[x]){ int l=son[x][0],r=son[x][1]; swap(son[x][0],son[x][1]); rev[l]^=1,rev[r]^=1,rev[x]^=1; } } void Rotate(int x){ int y=pre[x],z=pre[y],l,r; if (son[y][0]==x) l=0; else l=1; r=l^1; if (!isroot(y)) if (son[z][0]==y) son[z][0]=x; else son[z][1]=x; pre[x]=z; pre[y]=x; pre[son[x][r]]=y; son[y][l]=son[x][r]; son[x][r]=y; up(y); } void splay(int x){ int y,z,top=0; stk[++top]=x; for (int i=x;!isroot(i);i=pre[i]) stk[++top]=pre[i]; while (top) down(stk[top--]); while (!isroot(x)){ y=pre[x],z=pre[y]; if (!isroot(y)) if (son[y][0]==x^son[z][0]==y) Rotate(x); else Rotate(y); Rotate(x); } up(x); } void access(int x){ for (int y=0;x;y=x,x=pre[x]) splay(x),son[x][1]=y,up(x); } void makeroot(int x){ access(x),splay(x); rev[x]^=1; } void split(int x,int y){ makeroot(x); access(y),splay(y); } int findroot(int x){ access(x),splay(x); while (son[x][0]) x=son[x][0]; return x; } bool sameset(int x,int y){ return findroot(x)==findroot(y); } void cut(int x,int y){ split(x,y); cnt[x]--,cnt[y]--; pre[x]=son[y][0]=0; up(y); } void link(int x,int y){ makeroot(x); cnt[x]++,cnt[y]++; pre[x]=y; } int querymax(int x,int y){ split(x,y); return Max[y]; } }LCT[15]; int main(){ n=read(),m=read(),C=read(),K=read(); for (int i=1;i<=n;i++) v[i]=read(); int opt,x,y,w; Edge t1; while (m--){ x=read(),y=read(),w=read(); if (x>y) swap(x,y); t1=(Edge){x,y},E[t1]=w; LCT[w].link(x,y); } while (K--){ opt=read(); if (!opt){ x=read(),y=read(); v[x]=y; for (int i=0;i<C;i++) LCT[i].splay(x); } else if (opt==1){ x=read(),y=read(),w=read(); if (x>y) swap(x,y); t1=(Edge){x,y}; if (!E.count(t1)){ puts("No such edge."); continue; } if (E[t1]==w){ puts("Success."); continue; } if (LCT[w].cnt[x]>=2 || LCT[w].cnt[y]>=2){ puts("Error 1."); continue; } if (LCT[w].sameset(x,y)){ puts("Error 2."); continue; } puts("Success."); int tmp=E[t1]; LCT[tmp].cut(x,y),LCT[w].link(x,y); E[t1]=w; t1=(Edge){y,x}; E[t1]=w; } else{ w=read(),x=read(),y=read(); if (x==y) printf("%d\n",v[x]); else if (!LCT[w].sameset(x,y)) puts("-1"); else printf("%d\n",LCT[w].querymax(x,y)); } } return 0; }