题目描述
有一个无向图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.”。
- 对于查询操作,直接输出一个整数。
输入输出样例
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 – 4,故max{v1, v2, v4} = max{ 1, 2, 4 } = 4。
将连接节点1和节点2的边修改为颜色1,修改成功,输出“Success.”
将连接节点4和节点3的边修改为颜色1,由于修改后会使得存在由颜色1构成的环( 1 – 2 – 4 – 3 – 1 ),不满足条件2,故不修改,并输出“Error 2”。
不存在颜色0构成的从节点1到节点4的边,输出“-1”。
将连接节点2和节点3的边修改为颜色1,由于修改后节点2的连出去的颜色为1的边有3条,故不满足条件1,故不修改,并输出“Error 1.”。
将节点2的权值修改为5。
由颜色1构成的从节点1到节点4的路径有 1 – 2 – 4,故max{v1, v2, v4} = max{ 1, 5, 4 } = 5。
【数据规模】
对于30%的数据:N ≤ 1000,M ≤ 10000,C ≤ 10,K ≤ 1000。
另有20%的数据:N ≤ 10000,M ≤ 100000,C = 1,K ≤ 100000。
对于100%的数据:N ≤ 10000,M ≤ 100000,C ≤ 10,K ≤ 100000。
题面是洛谷上的……
这题可以说LCT里面的难题了吧……(蒟蒻)
整理一下题目的要求:
1.判断是否存在一个节点连出去>=3条以上的相同色边;
2.判断是否存在一个由相同色边构成的环;
3.更改一个点u的权值;
4.更改u~v之间的边颜色;
5.查询u~v之间由同一色w构成的简单路径(树)中经过点的最大权值。
6.判断u->v的边是否存在。
首先如果颜色只有一种(%20的数据),那么建立一个LCT就可以了。
我们先讨论这种情况。
这种情况下如何维护呢?
对于1,只要记录一下每个点的入度,然后在更改之前判断点的入度是否已经>=2即可;
对于2,在连接u和v之前,如果u和v已经联通,那么加入这条边肯定会成环;
对于3,直接更改,并且splay(全部up)u一遍;
对于4,待会儿讨论;
对于5,在LCT中维护最大值即可。
对于6,放到map里面(类似哈希)判断就好了
那么多种颜色呢?我们观察到颜色最多10种。
那直接建立10个LCT不就好了……
在4的修改上,我们求出原来边的颜色是q,要更改成w,
那么我们只要在LCT[q]里面删除这条边,然后在LCT[w]里面连上就好了。
同样地,3的地方我们也要进行更改:所有的LCT里面的u都要splay一遍。
差不多思想就好了,但是此题还有一些细节……
首先,如何保存原来的边的颜色呢?
我们用一个map存储就好了。
然后,此题有个坑!
就是更改的颜色可能=原来的颜色!
这种情况success。。
那么特判吧……然而!
特别判断的顺序也有关系…………
必须在判断no such edge之后!!
气啊……
#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;
}