码迷,mamicode.com
首页 > 其他好文 > 详细

[UOJ207]共价大爷游长沙

时间:2018-01-25 00:23:32      阅读:159      评论:0      收藏:0      [点我收藏+]

标签:size   can   style   ret   直接   class   lct   int   等于   

如果每次加入点对$(x,y)$,就给它一个随机的权值$v$,把两个点的点权都异或$v$,查询$(x,y)$的时候,只要把$x$硬点为根,以$y$为根的子树的异或和等于当前所有的异或和,那么很大概率就是正确的(每对点刚好有一个在$y$的子树中)

所以直接用lct维护即可,因为维护了虚边信息,所以link时两边都要makeroot(不然没法更新splay里的祖先的信息),cut时不改虚边信息

splay之前一定要记得一路pushdown啊啊啊啊啊啊!

#include<stdio.h>
#include<stdlib.h>
int ch[100010][2],fa[100010],r[100010],v[100010],s[100010],vs[100010],q1[300010],q2[300010],d[300010];
#define ls ch[x][0]
#define rs ch[x][1]
void swap(int&a,int&b){a^=b^=a^=b;}
void rev(int x){
	swap(ls,rs);
	r[x]^=1;
}
bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
void pushdown(int x){
	if(r[x]){
		if(ls)rev(ls);
		if(rs)rev(rs);
		r[x]=0;
	}
}
void pushup(int x){s[x]=v[x]^s[ls]^s[rs]^vs[x];}
void rot(int x){
	int y,z,f,B;
	y=fa[x];
	z=fa[y];
	f=(ch[y][0]==x);
	B=ch[x][f];
	fa[x]=z;
	fa[y]=x;
	if(B)fa[B]=y;
	ch[x][f]=y;
	ch[y][f^1]=B;
	if(ch[z][0]==y)ch[z][0]=x;
	if(ch[z][1]==y)ch[z][1]=x;
	pushup(y);
	pushup(x);
}
void gao(int x){
	if(!isrt(x))gao(fa[x]);
	pushdown(x);
}
void splay(int x){
	int y,z;
	gao(x);
	while(!isrt(x)){
		y=fa[x];
		z=fa[y];
		if(!isrt(y))rot((ch[z][0]==y&&ch[y][0]==x)||(ch[z][1]==y&&ch[y][1]==x)?y:x);
		rot(x);
	}
}
void access(int x){
	int y=0;
	while(x){
		splay(x);
		vs[x]^=s[rs];
		rs=y;
		vs[x]^=s[y];
		pushup(x);
		y=x;
		x=fa[x];
	}
}
void makert(int x){
	access(x);
	splay(x);
	rev(x);
}
void link(int x,int y){
	makert(x);
	makert(y);
	fa[x]=y;
	vs[y]^=s[x];
	pushup(y);
}
void cut(int x,int y){
	makert(y);
	access(x);
	splay(x);
	fa[y]=ls=0;
	pushup(x);
}
void modify(int x,int d){
	access(x);
	splay(x);
	v[x]^=d;
	pushup(x);
}
int query(int x,int y){
	makert(x);
	access(y);
	return vs[y]^v[y];
}
int main(){
	srand(19260817);
	int n,m,i,x,y,sum;
	scanf("%d%d%d",&i,&n,&m);
	for(i=1;i<n;i++){
		scanf("%d%d",&x,&y);
		link(x,y);
	}
	n=sum=0;
	while(m--){
		scanf("%d",&i);
		if(i==1){
			scanf("%d%d",&x,&y);
			cut(x,y);
			scanf("%d%d",&x,&y);
			link(x,y);
		}
		if(i==2){
			n++;
			scanf("%d%d",q1+n,q2+n);
			d[n]=x=rand()*rand();
			sum^=x;
			modify(q1[n],x);
			modify(q2[n],x);
			
		}
		if(i==3){
			scanf("%d",&x);
			modify(q1[x],d[x]);
			modify(q2[x],d[x]);
			sum^=d[x];
		}
		if(i==4){
			scanf("%d%d",&x,&y);
			puts(query(x,y)==sum?"YES":"NO");
		}
	}
}

[UOJ207]共价大爷游长沙

标签:size   can   style   ret   直接   class   lct   int   等于   

原文地址:https://www.cnblogs.com/jefflyy/p/8343626.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!