uoj#207 共价大爷游长沙
2017-05-30 16:29
302 查看
题面:http://uoj.ac/problem/207
正解:$link-cut tree$
这题的正解比较玄学。。
我们可以对于每一条路径随机一个权值,两个端点分别异或这个权值。
于是判断一条边是否在所有路径上,只需判断其中一个点的子树异或和是不是等于所有路径的异或和就行了。这个正确率是很高的。。
然后就有一个问题了,如何用动态树来维护子树?
其实很简单。。我们可以另外维护一下一个结点所有虚儿子的子树异或和。这样,我们就可以维护这个点在$LCT$上整棵子树了。我们只需在$access$,$link$操作中加一些东西,就能维护虚子树了。
查询子树的时候,我们只需把当前点$access$,查询虚子树异或和,此时的虚子树一定是它在原树中的子树。一些细节详见代码注释。。
另外推荐一个讲得比较好的博客:http://blog.csdn.net/neither_nor/article/details/52979425
正解:$link-cut tree$
这题的正解比较玄学。。
我们可以对于每一条路径随机一个权值,两个端点分别异或这个权值。
于是判断一条边是否在所有路径上,只需判断其中一个点的子树异或和是不是等于所有路径的异或和就行了。这个正确率是很高的。。
然后就有一个问题了,如何用动态树来维护子树?
其实很简单。。我们可以另外维护一下一个结点所有虚儿子的子树异或和。这样,我们就可以维护这个点在$LCT$上整棵子树了。我们只需在$access$,$link$操作中加一些东西,就能维护虚子树了。
查询子树的时候,我们只需把当前点$access$,查询虚子树异或和,此时的虚子树一定是它在原树中的子树。一些细节详见代码注释。。
另外推荐一个讲得比较好的博客:http://blog.csdn.net/neither_nor/article/details/52979425
//It is made by wfj_2048~ #include <algorithm> #include <iostream> #include <complex> #include <cstring> #include <cstdlib> #include <cstdio> #include <vector> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #define inf (1<<30) #define N (300010) #define il inline #define RG register #define ll long long #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) using namespace std; struct edge{ int x,y,z; }e ; int ch [2],fa ,sum ,val ,rev ,st ,n,m,S,tot; //val为x和虚子树的异或和,sum为x在lct中子树异或和。 il int gi(){ RG int x=0,q=1; RG char ch=getchar(); while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); if (ch=='-') q=-1,ch=getchar(); while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); return q*x; } il int isroot(RG int x){ return ch[fa[x]][0]!=x && ch[fa[x]][1]!=x; } il void pushup(RG int x){ sum[x]=sum[ch[x][0]]^sum[ch[x][1]]^val[x]; return; } il void pushdown(RG int x){ rev[x]=0,swap(ch[x][0],ch[x][1]); rev[ch[x][0]]^=1,rev[ch[x][1]]^=1; return; } il void rotate(RG int x){ RG int y=fa[x],z=fa[y],k=ch[y][0]==x; if (!isroot(y)) ch[z][ch[z][1]==y]=x; fa[x]=z,ch[y][k^1]=ch[x][k],fa[ch[x][k]]=y; fa[y]=x,ch[x][k]=y,pushup(y),pushup(x); return; } il void splay(RG int x){ RG int top=0; st[++top]=x; for (RG int i=x;!isroot(i);i=fa[i]) st[++top]=fa[i]; for (RG int i=top;i;--i) if (rev[st[i]]) pushdown(st[i]); while (!isroot(x)){ RG int y=fa[x],z=fa[y]; if (!isroot(y)){ if ((ch[z][0]==y)^(ch[y][0]==x)) rotate(x); else rotate(y); } rotate(x); } return; } //access的时候,我们需要改变虚子树异或和。 il void access(RG int x){ RG int t=0; while (x){ splay(x),val[x]^=sum[ch[x][1]]; val[x]^=sum[ch[x][1]=t]; pushup(x),t=x,x=fa[x]; } return; } il void makeroot(RG int x){ access(x),splay(x),rev[x]^=1; return; } //link的时候,y也要makeroot,不然没法维护y的祖先的val和sum。 il void link(RG int x,RG int y){ makeroot(x),makeroot(y),fa[x]=y; val[y]^=sum[x],pushup(y); return; } il void cut(RG int x,RG int y){ makeroot(x),access(y),splay(y); ch[y][0]=fa[x]=0,pushup(y); return; } il void update(RG int x,RG int v){ access(x),splay(x),val[x]^=v,sum[x]^=v; return; } //access以后,val维护的就是原子树异或和。 il int query(RG int x,RG int y){ makeroot(x),access(y); return val[y]==S ? 1 : 0; } il void work(){ n=gi(),n=gi(),m=gi(); for (RG int i=1,x,y;i<n;++i) x=gi(),y=gi(),link(x,y); for (RG int i=1,x,y,z,opt;i<=m;++i){ opt=gi(); if (opt==1){ x=gi(),y=gi(),cut(x,y); x=gi(),y=gi(),link(x,y); } if (opt==2){ x=gi(),y=gi(); e[++tot]=(edge){x,y,z=rand()}; update(x,z),update(y,z),S^=z; } if (opt==3){ x=gi(),S^=e[x].z; update(e[x].x,e[x].z),update(e[x].y,e[x].z); } if (opt==4){ x=gi(),y=gi(); puts(query(x,y) ? "YES" : "NO"); } } return; } int main(){ File("changsha"); srand(time(NULL)); work(); return 0; }
相关文章推荐
- 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息
- UOJ#207 共价大爷游长沙
- UOJ#207:共价大爷游长沙(LCT维护子树信息)
- [UOJ#207]共价大爷游长沙
- 【uoj207】 共价大爷游长沙
- 【UOJ207】共价大爷游长沙(Link-Cut Tree,随机化)
- UOJ207 共价大爷游长沙
- UOJ #207. 共价大爷游长沙
- [UOJ207]共价大爷游长沙
- UOJ #207. 共价大爷游长沙(不用维护子树的LCT)
- 共价大爷游长沙
- uoj#207. 共价大爷游长沙
- UOJ207:共价大爷游长沙
- UOJ #207. 共价大爷游长沙
- UOJ 207 共价大爷游长沙
- UOJ207:共价大爷游长沙
- UOJ #207. 共价大爷游长沙 [lct 异或]
- [UOJ207]共价大爷游长沙(随机,动态树维护子树和)
- 【UOJ #207】共价大爷游长沙