P2173 [ZJOI2012] 网络
P2173 [ZJOI2012] 网络
题目描述
有一个无向图
1、 对于任意节点连出去的边中,相同颜色的边不超过两条。
2、图中不存在同色的环,同色的环指相同颜色的边构成的环。
在这个图上,你要支持以下三种操作:
-
0 x y
表示把节点 的权值改为 -
1 u v w
表示将边 的颜色改为 。 -
2 c u v
表示查询由颜色 的边构成的图中,所有可能在 之间的简单路径上的节点的权值的最大值。
输入格式
第一行四个正整数
接下来
之后
最后
输出格式
输出若干行,每行输出一个对应的信息。
1、 对于修改节点权值操作,不需要输出信息。
2、对于修改边的颜色操作,按以下几类输出:
-
若不存在连接节点
和节点 的边,输出No such edge.
。 -
若修改后不满足条件
,不修改边的颜色,并输出Error 1.
。 -
若修改后不满足条件
,不修改边的颜色,并输出Error 2.
。 -
其他情况,成功修改边的颜色,并输出
Success.
。
输出满足条件的第一条信息即可,即若同时不满足条件 Error 1.
。
3、 对于查询操作,输出一个整数表示答案。若
【数据范围】
对于
说句闲话
终于写到 LCT 了,我自己都没想到我居然欠了这么多解题报告没写,感觉今天补不完啊 QAQ.
Solution:
首先我们狠狠阅读一下题目:
1、 对于任意节点连出去的边中,相同颜色的边不超过两条。
2、图中不存在同色的环,同色的环指相同颜色的边构成的环。
这启示我们针对每个颜色建一颗 LCT.然后就很板子了:
操作1我们就直接改颜色,操作二在经过一系列判断之后把原颜色的 LCT 上的边删掉,然后在新的颜色的 LCT 上加边,操作3直接 splite 就行。
操作2的“一系列操作”详见代码。
Code:
#include<bits/stdc++.h> const int N=1e5+5; const int C=10; using namespace std; int st[N]; int Max(int x,int y){return x>y ? x : y;} int w[N]; struct LCT{ struct Tree{ int mx,val,tag,ff,ch[2]; }t[N<<2]; #define ls t[x].ch[0] #define rs t[x].ch[1] #define fa t[x].ff inline bool isroot(int x) { return (t[fa].ch[0]==x||t[fa].ch[1]==x); } inline void pushup(int x) { t[x].mx=Max(Max(t[ls].mx,t[rs].mx),t[x].val); return; } inline void rev(int x) { swap(t[x].ch[0],t[x].ch[1]); t[x].tag^=1; return ; } inline void pushdown(int x) { if(t[x].tag) { if(ls)rev(ls); if(rs)rev(rs); t[x].tag=0; } return ; } inline void rotate(int x) { int y=fa,z=t[fa].ff,k=t[fa].ch[1]==x ? 1 : 0; if(isroot(y))t[z].ch[t[z].ch[1]==y]=x; t[x].ff=z; t[y].ch[k]=t[x].ch[!k]; if(t[x].ch[!k])t[t[x].ch[!k]].ff=y; t[x].ch[!k]=y; t[y].ff=x; pushup(y); } inline void splay(int x) { int y=x,z=0; st[++st[0]]=y; while(isroot(y))st[++st[0]]=y=t[y].ff; while(st[0])pushdown(st[st[0]--]); while(isroot(x)&&x)//isn't root { y=fa,z=t[fa].ff; if(isroot(y)){rotate((t[y].ch[1]==x)==(t[z].ch[1]==y) ? y : x);} rotate(x); } pushup(x); } void access(int x) { int y=0; while(x) { splay(x);rs=y;pushup(x); y=x;x=fa; } } void make_root(int x)//换根 { access(x);splay(x); rev(x); } int find(int x) { access(x);splay(x); while(ls)pushdown(x),x=ls; splay(x); return x; } bool splite(int x,int y) { make_root(x); if(find(y)!=x)return 0; access(y);splay(y); return 1; } bool link(int x,int y)// 意义很明确的函数名称 { make_root(x); if(find(y)!=x){t[x].ff=y;return 1;} return 0; } bool cut(int x,int y)// 意义很明确的函数名称 { make_root(x); if(find(y)==x&&t[y].ff==x&&t[y].ch[0]==0) { t[y].ff=t[x].ch[1]=0; pushup(x); return 1; } return 0; } }T[C]; int d[C][N]; int n,m,p,q; map<pair<int,int>,int> Map; #define mp(x,y) make_pair(x,y) void work() { cin>>n>>m>>p>>q; for(int i=1;i<=n;i++) { scanf("%d",&w[i]); } for(int j=0;j<p;j++)for(int i=1;i<=n;i++)T[j].t[i].val=T[j].t[i].mx=w[i]; for(int i=1,x,y,col;i<=m;i++) { scanf("%d%d%d",&x,&y,&col); T[col].link(x,y);d[col][x]++;d[col][y]++; Map[mp(x,y)]=col+1; Map[mp(y,x)]=col+1; } int opt,x,y,z; for(int i=1;i<=q;i++) { scanf("%d%d%d",&opt,&x,&y); if(opt==0) { w[x]=y; for(int j=0;j<p;j++) { T[j].t[x].val=w[x]; T[j].splay(x); } continue; } scanf("%d",&z); if(opt==1) { if(z==Map[mp(x,y)]-1){printf("Success.\n");continue;} if(!Map[mp(x,y)]){printf("No such edge.\n");continue;} if(d[z][x]==2||d[z][y]==2){printf("Error 1.\n");continue;} if(T[z].link(x,y)) { int col=Map[mp(x,y)]-1;Map[mp(x,y)]=Map[mp(y,x)]=z+1; T[col].cut(x,y); d[col][x]--,d[col][y]--; d[z][x]++,d[z][y]++; printf("Success.\n"); } else {printf("Error 2.\n");} } if(opt==2) { if(T[x].splite(y,z)) { printf("%d\n",Max(T[x].t[z].mx,T[x].t[z].val)); } else { printf("%d\n",-1); } } } } int main() { //freopen("network.in","r",stdin); //freopen("network.out","w",stdout); work(); return 0; }