Luogu 2173 [ZJOI2012]网络

传送门
这是一道函数很杂的LCT题。(有点类似Qtree6,Qtree7。但略难。)

思路:

c那么小,直接建c棵树。

处理方式:

  1. 更改每棵树上该点的值。
  2. 最难点。先找到边的颜色(一颗一颗找),如果找不到,输出“No such edge.”。
    如果边的颜色与更改后的相同,输出“Success.”。
    c n t [ x ] [ y ] x y cnt[x][y]表示与x相连的颜色为y的边的边数 ,就可以方便地判“Error 1.”
    设变化后的颜色为w,若在对应的树上两个点已经联通,则输出“Error 2.“
    最后,删边建边,输出“Success."就行。
  3. splay节点加一个mx参数即可。

代码:

#include<cstdio>
#include<cctype>
#include<cstring>
#include<algorithm>
#define g g()
#define lc tr[x].son[0]
#define rc tr[x].son[1]
using namespace std;
const int N=1e4+10,inf=0x7fffffff,size=1<<25;
int d[N];struct node{int f,son[2],mx;bool v;};
int n,m,c,k;char cnt[N][12];
struct Link_Cut_Tree{
	node tr[N];
	void update(int x){tr[x].mx=max(d[x],max(tr[lc].mx,tr[rc].mx));}
	void fz(int x){//翻转 
		tr[x].v=0;swap(lc,rc);
		tr[lc].v^=1;tr[rc].v^=1;
	}
	bool rt(int x){return tr[tr[x].f].son[0]!=x&&tr[tr[x].f].son[1]!=x;}//是否为根 
	void dfs(int x){//递归维护 
		if(!rt(x))dfs(tr[x].f);
		if(tr[x].v)fz(x);
	}
	void rotate(int x,int w){//旋转 
		int f=tr[x].f,ff=tr[f].f,r,R;
		r=tr[x].son[w];R=f;tr[R].son[1-w]=r;if(r)tr[r].f=R;
		r=x;R=ff;if(tr[R].son[0]==f)tr[R].son[0]=r;else if(tr[R].son[1]==f)tr[R].son[1]=r; tr[r].f=R;
		r=f;R=x;tr[R].son[w]=r;tr[r].f=R;update(f);update(x);
	}
	void splay(int x){
		dfs(x);
		while(!rt(x)){
			int f=tr[x].f;
			if(rt(f))rotate(x,tr[f].son[0]==x);
			else{
				int ff=tr[f].f,a=(tr[f].son[0]==x),b=(tr[ff].son[0]==f);
				if(a^b)rotate(x,a),rotate(x,b);
				else rotate(f,a),rotate(x,a);
			}
		}
	}
	void access(int x){for(int y=0;x;x=tr[y=x].f)splay(x),rc=y,update(x);}
	void makeroot(int x){access(x);splay(x);tr[x].v^=1;}
	int find_root(int x){access(x);splay(x);while(lc)x=lc;return x;}
	void split(int x,int y){makeroot(y);access(x);splay(x);}
	bool connect(int x,int y){split(x,y);return lc==y&&(!tr[y].son[1]);}//x,y是否有边连接 
	bool unicom(int x,int y){split(x,y);while(lc)x=lc;return x==y;}//判联通 
	void link(int x,int y){makeroot(x);tr[x].f=y;access(x);}
	void cut(int x,int y){split(x,y);lc=0;tr[y].f=0;update(x);}
	int query(int x,int y){return unicom(x,y)?tr[x].mx:-1;}
}lct[12];
//0
void change(int x,int w){
	d[x]=w;
	for(int i=0;i<c;i++)lct[i].access(x),lct[i].splay(x),lct[i].update(x);
}
//1
void color(int x,int y,int w){
	int z=-1;
	for(int i=0;i<c;i++)if(lct[i].connect(x,y)){z=i;break;}//有了splay,用什么map查边(常数那么大) 
	if(z==w){puts("Success.");return;}//坑点 
	if(z<0){puts("No such edge.");return;}
	if((cnt[x][w]>=2||cnt[y][w]>=2)){puts("Error 1.");return;}//
	if(lct[w].unicom(x,y)){puts("Error 2.");return;}
	lct[z].cut(x,y); cnt[x][z]--;cnt[y][z]--;
	lct[w].link(x,y);cnt[x][w]++;cnt[y][w]++;
	puts("Success.");
}
//2
int ask(int w,int x,int y){return lct[w].query(x,y);}

char buf[size],*p1=buf,*p2=buf;
char g{return p1==p2&&(p2=(p1=buf)+fread(buf,1,size,stdin),p1==p2)?EOF:*p1++;}
void qr(int &x){
	char c=g;bool v=x=0;
	while(!(isdigit(c)||c=='-'))c=g;
	if(c=='-')v=1,c=g;
	while(isdigit(c))x=x*10+c-'0',c=g;
	if(v)x=-x;
}
void write(int x){
	if(x/10)write(x/10);
	putchar(x%10+'0');
}
void pri(int x){
	if(x<0)putchar('-'),x=-x;
	write(x);puts("");
}

int main(){
	qr(n);qr(m);qr(c);qr(k);
	for(int j=0;j<c;j++)lct[j].tr[0].mx=-inf;//初始化 
	for(int i=1;i<=n;i++){
		qr(d[i]);
		for(int j=0;j<c;j++)lct[j].tr[i].mx=d[i];//初始化 
	}
	int op,x,y,w;
	while(m--)qr(x),qr(y),qr(w),lct[w].link(x,y),cnt[x][w]++,cnt[y][w]++;
	while(k--){
		qr(op);
		switch(op){
			case 0:qr(x);qr(y);change(x,y);break;
			case 1:qr(x);qr(y);qr(w);color(x,y,w);break;
			case 2:qr(w);qr(x);qr(y);pri(ask(w,x,y));break;
		}
	}
	return 0;
}
发布了71 篇原创文章 · 获赞 88 · 访问量 5488

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/98304630