UOJ#207:共价大爷游长沙(LCT维护子树信息)
2017-12-27 20:41
330 查看
题面
题意:一颗树,要求支持加边删边,加入和删除路径,询问是否所有路径都经过某条边。
我一开始想到维护联通块内的起点数与终点数,以及路径加减,但是都有反例。
应该是一种套路的我没听说过的做法。
为每条路径随机一个rp值,在两个点上异或这个值,维护子树异或和就好了。
还有一种做法是把rp异或到路径上。删边时把整条路径异或这条边的rp值。
看似很随意,但直到我想清楚为什么路径+1会错时,才发现这个方法好机巧。
对于经过删去的边(u,v)和删去后路径(u,v)上的任意一条边E。
对于删边前经过(u,v)的路径,若删边前经过E,则删边后不过E,反之也是。
充分利用了异或相同为0的特点。
我好久没写过LCT维护子树信息了,就写了第一种。
题意:一颗树,要求支持加边删边,加入和删除路径,询问是否所有路径都经过某条边。
我一开始想到维护联通块内的起点数与终点数,以及路径加减,但是都有反例。
应该是一种套路的我没听说过的做法。
为每条路径随机一个rp值,在两个点上异或这个值,维护子树异或和就好了。
还有一种做法是把rp异或到路径上。删边时把整条路径异或这条边的rp值。
看似很随意,但直到我想清楚为什么路径+1会错时,才发现这个方法好机巧。
对于经过删去的边(u,v)和删去后路径(u,v)上的任意一条边E。
对于删边前经过(u,v)的路径,若删边前经过E,则删边后不过E,反之也是。
充分利用了异或相同为0的特点。
我好久没写过LCT维护子树信息了,就写了第一种。
#include <iostream> #include <fstream> #include <algorithm> #include <cmath> #include <ctime> #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; #define mmst(a, b) memset(a, b, sizeof(a)) #define mmcp(a, b) memcpy(a, b, sizeof(b)) typedef long long LL; const int N=200200; int n,m,now,cnt; int u ,v ,rp ; void read(int &hy) { hy=0; char cc=getchar(); while(cc<'0'||cc>'9') cc=getchar(); while(cc>='0'&&cc<='9') { hy=(hy<<3)+(hy<<1)+cc-'0'; cc=getchar(); } } struct tree { int a,aa; bool flip; tree *c[2],*pp,*f; int d(){return f->c[1]==this;} void sc(tree *x,int d){(c[d]=x)->f=this;} }nil ,*ro ; void down(tree *x) { if(x->flip) { x->flip=0; swap(x->c[0],x->c[1]); x->c[0]->flip^=1; x->c[1]->flip^=1; } } void work(tree *x) { if(x->f!=nil) work(x->f); down(x); } void up(tree *x) { x->aa=x->a^x->c[0]->aa^x->c[1]->aa; } void zig(tree *x) { int d=x->d(); tree *y=x->f; y->sc(x->c[!d],d); if(y->f==nil) x->f=nil; else y->f->sc(x,y->d()); x->sc(y,!d); x->pp=y->pp; y->pp=nil; up(y); up(x); } void splay(tree *x) { work(x); for(tree *y;x->f!=nil;) { y=x->f; if(y->f!=nil) (x->d() ^ y->d()) ? zig(x) : zig(y); zig(x); } } void Access(tree *x) { tree *y=nil; while(x!=nil) { splay(x); if(x->c[1]!=nil) { x->c[1]->f=nil; x->c[1]->pp=x; x->a^=x->c[1]->aa; } x->c[1]=y; if(y!=nil) y->f=x; x->a^=y->aa; up(x); y->pp=nil; y=x; x=x->pp; } } void Evert(tree *x) { Access(x); splay(x); x->flip^=1; } void Link(tree *x,tree *y) { Evert(x); splay(x); Access(y); splay(y); x->pp=y; y->a^=x->aa; up(y); } void Cut(tree *x,tree *y) { Evert(x); Access(y); splay(x); x->c[1]->f=nil; x->c[1]=nil; up(x); } void BBQ(tree *x,int oi) { Access(x); splay(x); x->a^=oi; up(x); } int main() { srand(time(0)); nil->c[0]=nil->c[1]=nil->f=nil->pp=nil; cin>>n; cin>>n>>m; for(int i=1;i<=n;i++) { nil[i]=nil[0]; ro[i]=nil+i; } for(int i=1;i<n;i++) { int uu,vv; read(uu); read(vv); Link(ro[uu],ro[vv]); } for(int i=1;i<=m;i++) { int ops,uu,vv; read(ops); if(ops==1) { read(uu); read(vv); Cut(ro[uu],ro[vv]); read(uu); read(vv); Link(ro[uu],ro[vv]); } if(ops==2) { cnt++; rp[cnt]=rand()*rand(); now^=rp[cnt]; read(u[cnt]); read(v[cnt]); BBQ(ro[u[cnt]],rp[cnt]); BBQ(ro[v[cnt]],rp[cnt]); } if(ops==3) { read(uu); now^=rp[uu]; BBQ(ro[u[uu]],rp[uu]); BBQ(ro[v[uu]],rp[uu]); } if(ops==4) { read(uu); read(vv); Evert(ro[uu]); Access(ro[vv]); splay(ro[vv]); if(ro[vv]->a==now) printf("YES\n"); else printf("NO\n"); } } return 0; }
相关文章推荐
- 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息
- UOJ #207. 共价大爷游长沙(不用维护子树的LCT)
- [UOJ207]共价大爷游长沙(随机,动态树维护子树和)
- BZOJ4530 BJOI 2014 大融合 LCT维护子树信息
- [BZOJ4530]-大融合-LCT维护子树信息
- UOJ #207. 共价大爷游长沙 [lct 异或]
- BZOJ 3510: 首都 LCT维护子树信息 启发式合并
- bzoj 4530: [Bjoi2014]大融合 lct维护子树信息
- [BZOJ]4530 [BJOI2014] 大融合 LCT维护子树信息
- LCT维护子树信息(子树信息LCT) LCT维护边权(边权LCT) 知识点讲解
- [UOJ#207]共价大爷游长沙
- bzoj4530 [Bjoi2014]大融合 (LCT维护子树信息)
- [BZOJ3510][启发式合并][LCT维护子树信息]首都
- [BZOJ4530][Bjoi2014][LCT维护子树信息]大融合
- LCT维护子树信息(BZOJ4530:[BJOI2014]大融合)
- uoj#207 共价大爷游长沙
- bzoj3510首都 LCT维护子树信息+启发式合并
- 【BZOJ4530】[Bjoi2014]大融合 LCT维护子树信息
- 【BZOJ3510】首都 LCT维护子树信息+启发式合并
- BZOJ 3779 重组病毒 LCT维护子树信息