[ZJOI2012]网络

Posted by Dispwnl on March 18, 2018

题目

题目描述

有一个无向图G,每个点有个权值,每条边有一个颜色。这个无向图满足以下两个条件:

1.对于任意节点连出去的边中,相同颜色的边不超过两条。

2.图中不存在同色的环,同色的环指相同颜色的边构成的环。

在这个图上,你要支持以下三种操作:

0.修改一个节点的权值。

1.修改一条边的颜色。

2.查询由颜色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

输出样例#1:

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$,先把点加入每个$LCT$中,边加入对应的$LCT$中

我们看看每个操作:

0.就是修改点权,枚举颜色修改就行了

1.还是枚举每种颜色的$LCT$,如果这个$LCT$中$x$和$y$相连

先$split(x,y)$一下

如果此颜色=修改颜色$dis$,就不用修改直接输出”Success.”

对于判断是否满足条件1,我们用一个数组$d$记录$x$连出去颜色$i$的边有几条,即$d_{x,i}$

这样随时更新$d​$,如果$d_{x,dis}>1​$或$d_{y,dis}>1​$,就不满足,输出”Error 1.”

对于判断是否满足条件2,我们直接判断颜色编号为$dis​$的$LCT​$中$x​$和$y​$是否连通

如果连通,再加一条边肯定成同颜色环,就输出”Error 2.”

最后找不到就输出”No such edge.”

2.这个就是简单的输出了…如果在颜色编号为$dis$的$LCT$中不连通记得输出-1

代码

# include<iostream>
# include<cstring>
# include<cstdio>
# include<cstdlib>
using namespace std;
const int MAX=1e4+1;
int n,m,c,k;
int a[MAX];
int d[MAX][11];
struct Link_Cut_Tree{
	int w[MAX],fa[MAX];
	int son[MAX][2];
	bool fl[MAX];
	void pus(int x)
	{
		w[x]=max(max(w[son[x][0]],w[son[x][1]]),a[x]);
	}
	void down(int x)
	{
		if(fl[x]&&x)
		{
			if(son[x][1]) fl[son[x][1]]^=1;
			if(son[x][0]) fl[son[x][0]]^=1;
			swap(son[x][0],son[x][1]);
			fl[x]=0;
		}
	}
	bool is_root(int x)
	{
		return son[fa[x]][1]!=x&&son[fa[x]][0]!=x;
	}
	bool id(int x)
	{
		return son[fa[x]][0]==x?0:1;
	}
	void rot(int x)
	{
		int y=fa[x],z=fa[y],k=id(x);
		if(!is_root(y)) son[z][id(y)]=x;
		son[y][k]=son[x][k^1],fa[son[y][k]]=y;
		son[x][k^1]=y,fa[y]=x;
		fa[x]=z;
		pus(y),pus(x);
	}
	void PUS(int x)
	{
		if(!is_root(x)) PUS(fa[x]);
		down(x);
	}
	void splay(int x)
	{
		PUS(x);
		for(int y;!is_root(x);rot(x))
		  if(!is_root(y=fa[x]))
		  rot(id(x)==id(y)?y:x);
	}
	void access(int x)
	{
		for(int y=0;x;y=x,x=fa[x])
		  splay(x),son[x][1]=y,pus(x);
	}
	int find_root(int x)
	{
		access(x),splay(x);
		while(son[x][0]) x=son[x][0];
		return x;
	}
	void make_root(int x)
	{
		access(x),splay(x);
		fl[x]^=1;
	}
	void split(int x,int y)
	{
		make_root(x),access(y),splay(y);
	}
	void cut(int x,int y)
	{
		split(x,y);
		if(son[y][0]==x)
		son[y][0]=0,fa[x]=0;
	}
	void link(int x,int y)
	{
		make_root(x);
		fa[x]=y;
	}
	void change(int x,int dis)
	{
		access(x),splay(x);
		a[x]=dis;
		pus(x);
	}
}Tree[11];
void CHANGE(int x,int y,int dis)
{
	for(int i=1;i<=c;i++)
	  if(Tree[i].find_root(x)==Tree[i].find_root(y))
	  {
	  	Tree[i].split(x,y);
	  	if(Tree[i].son[y][0]!=x||Tree[i].son[x][1]) continue;
	  	if(i==dis)
	  	{
	  		printf("Success.\n");
	  		return;
		}
		if(d[x][dis]>1||d[y][dis]>1)
		{
			printf("Error 1.\n");
			return;
		}
		if(Tree[dis].find_root(x)==Tree[dis].find_root(y))
		{
			printf("Error 2.\n");
			return;
		}
		Tree[i].cut(x,y),Tree[dis].link(x,y);
		d[x][i]--,d[y][i]--;
		d[x][dis]++,d[y][dis]++;
		printf("Success.\n");
		return;
	  }
	printf("No such edge.\n");
}
int read()
{
	int x=0,f=1;
	char ch=getchar();
	for(;!isdigit(ch);f=(ch=='-')?-1:1,ch=getchar());
	for(;isdigit(ch);x=x*10+ch-48,ch=getchar());
	return x*f;
}
int main()
{
	n=read(),m=read(),c=read(),k=read();
	for(int i=1;i<=n;i++)
	  {
	  	a[i]=read();
	  	for(int j=1;j<=c;j++)
	  	  Tree[j].w[i]=a[i];
	  }
	for(int i=1;i<=m;i++)
	  {
	  	int x=read(),y=read(),dis=read()+1;
	  	d[x][dis]++,d[y][dis]++;
	  	Tree[dis].link(x,y);
	  }
	for(int i=1;i<=k;i++)
	  {
	  	int op=read(),x,y,dis;
	  	if(!op)
	  	{
	  		x=read(),y=read();
			for(int j=1;j<=c;j++)
	  		  Tree[j].change(x,y);
		}
		else if(op==1)
		{
			x=read(),y=read(),dis=read()+1;
			CHANGE(x,y,dis);
		}
		else if(op==2)
		{
			dis=read()+1,x=read(),y=read();
			if(Tree[dis].find_root(x)!=Tree[dis].find_root(y))
			printf("-1\n");
			else
			{
				Tree[dis].split(x,y);
				printf("%d\n",Tree[dis].w[y]);
			}
		}
	  }
	return 0;
}