[BZOJ4573][ZJOI2016]大♂森林
2018-04-08 22:44
435 查看
bzoj
luogu
uoj
考虑每两个相邻位置的树的差异。
对于一个1操作(更换生长节点),假设区间是\([l,r]\),那么第\(l-1\)棵树和第\(l\)棵数就会产生一定的差异,具体来说,假设在这之后没有1操作了,那么所有应该在第\(l-1\)棵树中接到原生长节点下面的点都在第\(l\)棵树中被接到了新的生长节点的下面。
我们考虑怎么快速实现这个操作。很显然,我们只要把修改了生长节点后新长出来的点打个包,然后\(cut\)再\(link\)一下就好了。
如果是一棵子树,直接对根节点进行操作就行了。
但是显然并不是一棵子树啊。
那就直接新建一个点把新建的点接在下面就好了。
具体来说,对于每一个1操作,新建一个虚点,把所有从这个生长节点长出来的点接在下面。
在处理到第\(l\)棵树时,把这个虚点接到那个生长节点的下面去;处理到第\(r+1\)棵树的时候再把虚点接到前一个生长节点对应的虚点上去。
这样就可以直接查询两个点的路径长度了。
但是有新建的虚点?
直接把实点的权值设为1,虚点的权值设为0,然后查路径和就好了。
但是这是一棵有根树,并不能\(split\)啊。
所以可以查\(s[x]+s[y]-2*s[lca(x,y)]\)?
现在的问题是:怎么在\(LCT\)查\(LCA\)?
先\(access(x)\),然后在\(access(y)\)的时候,最后一个由虚边改为实边的位置就是\(LCA\)。
这个画个图就能理解了吧。
然后这题就做完了。
luogu
uoj
sol
\(orz\ \ HJT\ \ dalao\)教会我做这道题。考虑每两个相邻位置的树的差异。
对于一个1操作(更换生长节点),假设区间是\([l,r]\),那么第\(l-1\)棵树和第\(l\)棵数就会产生一定的差异,具体来说,假设在这之后没有1操作了,那么所有应该在第\(l-1\)棵树中接到原生长节点下面的点都在第\(l\)棵树中被接到了新的生长节点的下面。
我们考虑怎么快速实现这个操作。很显然,我们只要把修改了生长节点后新长出来的点打个包,然后\(cut\)再\(link\)一下就好了。
如果是一棵子树,直接对根节点进行操作就行了。
但是显然并不是一棵子树啊。
那就直接新建一个点把新建的点接在下面就好了。
具体来说,对于每一个1操作,新建一个虚点,把所有从这个生长节点长出来的点接在下面。
在处理到第\(l\)棵树时,把这个虚点接到那个生长节点的下面去;处理到第\(r+1\)棵树的时候再把虚点接到前一个生长节点对应的虚点上去。
这样就可以直接查询两个点的路径长度了。
但是有新建的虚点?
直接把实点的权值设为1,虚点的权值设为0,然后查路径和就好了。
但是这是一棵有根树,并不能\(split\)啊。
所以可以查\(s[x]+s[y]-2*s[lca(x,y)]\)?
现在的问题是:怎么在\(LCT\)查\(LCA\)?
先\(access(x)\),然后在\(access(y)\)的时候,最后一个由虚边改为实边的位置就是\(LCA\)。
这个画个图就能理解了吧。
然后这题就做完了。
code
#include<cstdio> #include<algorithm> using namespace std; int gi() { int x=0,w=1;char ch=getchar(); while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if (ch=='-') w=0,ch=getchar(); while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return w?x:-x; } const int N = 4e5+5; struct node{ int pos,tim,x,y; bool operator < (const node &b) const {return pos!=b.pos?pos<b.pos:tim<b.tim;} }q ; int n,m,cnt,Q,fa ,ch[2] ,val ,sum ,grow,real,tot,id ,L ,R ,ans ; bool son(int x){return x==ch[1][fa[x]];} bool isroot(int x) { return x!=ch[0][fa[x]]&&x!=ch[1][fa[x]]; } void pushup(int x) { sum[x]=sum[ch[0][x]]+sum[ch[1][x]]+val[x]; } void rotate(int x) { int y=fa[x],z=fa[y],c=son(x); ch[c][y]=ch[c^1][x];if (ch[c][y]) fa[ch[c][y]]=y; fa[x]=z;if (!isroot(y)) ch[son(y)][z]=x; ch[c^1][x]=y;fa[y]=x;pushup(y); } void splay(int x) { for (int y=fa[x];!isroot(x);rotate(x),y=fa[x]) if (!isroot(y)) son(x)^son(y)?rotate(x):rotate(y); pushup(x); } int access(int x) { int y=0; for (;x;y=x,x=fa[x]) splay(x),ch[1][x]=y,pushup(x); return y; } void link(int x,int y) { access(x);splay(x);fa[x]=y; } void cut(int x) { access(x);splay(x); ch[0][x]=fa[ch[0][x]]=0;pushup(x); } int main() { // freopen("a.in","r",stdin); // freopen("a.out","w",stdout); n=gi();m=gi();link(2,1);val[1]=1;id[1]=1; L[1]=1;R[1]=n;grow=tot=2;real=1; for (int i=1;i<=m;++i) { int opt=gi(),l=gi(),r=gi(); if (!opt) { link(id[++real]=++tot,grow);val[tot]=1; L[real]=l;R[real]=r; } if (opt==1) { int x=gi();l=max(l,L[x]),r=min(r,R[x]); if (l>r) continue; link(++tot,grow); q[++cnt]=(node){l,i-m,tot,id[x]};q[++cnt]=(node){r+1,i-m,tot,grow}; grow=tot; } if (opt==2) { int x=gi(); q[++cnt]=(node){l,++Q,id[r],id[x]}; } } sort(q+1,q+cnt+1); for (int i=1;i<=cnt;++i) if (q[i].tim>0) { int res,gg; access(q[i].x);splay(q[i].x);res=sum[q[i].x]; gg=access(q[i].y);splay(q[i].y);res+=sum[q[i].y]; access(gg);splay(gg);res-=sum[gg]<<1; ans[q[i].tim]=res; } else cut(q[i].x),link(q[i].x,q[i].y); for (int i=1;i<=Q;++i) printf("%d\n",ans[i]); return 0; }
相关文章推荐
- [bzoj4573][UOJ#195][ZJOI2016]大森林
- [BZOJ4573][ZJOI2016]大森林(LCT建虚点)
- [LCT || splay维护括号序列] BZOJ 4573 [Zjoi2016]大森林
- BZOJ4573 : [Zjoi2016]大森林
- Bzoj4573: [Zjoi2016]大森林
- [BZOJ4573][UOJ#195][Zjoi2016][LCT][离线]大森林
- BZOJ4573:[ZJOI2016]大森林——题解
- bzoj 4573: [Zjoi2016]大森林 lct
- [BZOJ4573][[Zjoi2016]大森林][LCT建虚点]
- bzoj 4573: [Zjoi2016]大森林
- bzoj 4456: [Zjoi2016]旅行者 分治+最短路
- BZOJ 4574: [Zjoi2016]线段树/UOJ #196. 【ZJOI2016】线段树 dp
- 【bzoj3349】[Zjoi2016]小星星
- BZOJ 4455: [Zjoi2016]小星星 [容斥原理 树形DP]
- [BZOJ4455][Zjoi2016]小星星(容斥原理+树形DP)
- 【BZOJ4456】[Zjoi2016]旅行者 分治+最短路
- BZOJ4456 ZJOI2016旅行者(分治+最短路)
- Bzoj4456 [Zjoi2016]旅行者
- BZOJ 4455: [Zjoi2016]小星星
- bzoj 4455: [Zjoi2016]小星星