bzoj4530 [Bjoi2014]大融合 (LCT维护子树信息)
2017-11-27 22:07
429 查看
bzoj4530 [Bjoi2014]大融合
原题地址:http://www.lydsy.com/JudgeOnline/problem.php?id=4530题意:
小强要在N个孤立的星球上建立起一套通信系统。这套通信系统就是连接N个点的一个树。
这个树的边是一条一条添加上去的。在某个时刻,一条边的负载就是它所在的当前能够
联通的树上路过它的简单路径的数量。
例如,在上图中,现在一共有了5条边。其中,(3,8)这条边的负载是6,因
为有六条简单路径2-3-8,2-3-8-7,3-8,3-8-7,4-3-8,4-3-8-7路过了(3,8)。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的
询问。
第一行包含两个整数N,Q,表示星球的数量和操作的数量。星球从1开始编号。
接下来的Q行,每行是如下两种格式之一:
A x y 表示在x和y之间连一条边。保证之前x和y是不联通的。
Q x y 表示询问(x,y)这条边上的负载。保证x和y之间有一条边。
数据范围
1≤N,Q≤100000
题解:
neither_nor学长的讲解
首先为了维护子树信息,我们需要维护每个点实子树和虚子树的信息。(实子树的信息包括实儿子的虚子树的信息)
为什么?
尽管一个点x的实子树中并不全是他原树的子树(例如他实际的fa),
但如果 access(x),则 x的虚子树就是原树中的x的子树。
因此,只需要维护子树信息(实/虚),access后查询即可。
改变虚子树信息的只是 access和link
这时的,update就是 自己信息+ls信息+rs信息+虚子树信息。
对于这道题:
就是 size = ls.size+rs.size+虚子树size+1
改变虚子树时要减掉改变的,加上连上的子树信息。
ans=size[x]*(size总-size[x])
注意:
link x到y上前,要先把其中一方makeroot,
这和bzoj2002不同,x和y都可能有原树的父亲,x可能有ls,即真实的fa,现在又来个fa显然不行。
另外link后也要update,因为虚子树改变了。
代码:
#include<cstdio> #include<iostream> #include<cstring> #include<algorithm> using namespace std; const int N=100005; int n,q; struct node { int ch[2],fa,size,ss; bool rev; void init() {fa=ch[1]=ch[0]=ss=0;rev=0;size=1;} }tr ; struct Link_Cut_Tree { bool isroot(int x) {return (tr[tr[x].fa].ch[0]!=x&&tr[tr[x].fa].ch[1]!=x);} void pushdown(int x) { if(tr[x].rev) { swap(tr[x].ch[0],tr[x].ch[1]); if(tr[x].ch[0]) tr[tr[x].ch[0]].rev^=1; if(tr[x].ch[1]) tr[tr[x].ch[1]].rev^=1; tr[x].rev^=1; } } void push(int x) { if(!isroot(x)) push(tr[x].fa); pushdown(x); } void update(int x) { int ls=tr[x].ch[0]; int rs=tr[x].ch[1]; tr[x].size=tr[x].ss+1+tr[ls].size+tr[rs].size; } void rotate(int x) { int y=tr[x].fa; int z=tr[y].fa; int l=(tr[y].ch[0]==x)?0:1; int r=l^1; if(!isroot(y)) {if(tr[z].ch[0]==y) tr[z].ch[0]=x; else tr[z].ch[1]=x;} tr[x].fa=z; tr[y].ch[l]=tr[x].ch[r]; tr[tr[x].ch[r]].fa=y; tr[x].ch[r]=y; tr[y].fa=x; update(y); update(x); } void splay(int x) { push(x); while(!isroot(x)) { int y=tr[x].fa; int z=tr[y].fa; if(!isroot(y)) { if((tr[y].ch[0]==x)^(tr[z].ch[0]==y)) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { int y=0; for(;x;y=x,x=tr[x].fa) { splay(x); tr[x].ss+=tr[tr[x].ch[1]].size; tr[x].ch[1]=y; tr[x].ss-=tr[y].size; update(x); } } void makeroot(int x) { access(x); splay(x); tr[x].rev=1; } void link(int x,int y) { makeroot(x); access(y); splay(y); //必须要makeroot[x] 因为若x不是根就有可能有原树上的fa,即ls,此时又加了一个fa,就有两个fa了。 tr[x].fa=y; tr[y].ss+=tr[x].size; update(y);//!!!!!! 这里size也包含虚树的,所以ss改变要update } }LCT; int main() { scanf("%d%d",&n,&q); for(int i=0;i<=n;i++) tr[i].init(); tr[0].size=0; while(q--) { char opt[5];int x,y; scanf("%s",opt); scanf("%d%d",&x,&y); if(opt[0]=='A') LCT.link(x,y); else { LCT.makeroot(x); LCT.access(y); LCT.splay(x); printf("%lld\n",1LL*(tr[y].ss+1)*(tr[x].size-tr[y].ss-1)); } } return 0; }
相关文章推荐
- LCT维护子树信息(BZOJ4530:[BJOI2014]大融合)
- [BZOJ4530][Bjoi2014][LCT维护子树信息]大融合
- BZOJ4530 BJOI 2014 大融合 LCT维护子树信息
- BZOJ 4530: [Bjoi2014]大融合 lct维护子树信息
- bzoj 4530: [Bjoi2014]大融合 lct维护子树信息
- 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息
- BZOJ4530:[BJOI2014]大融合(LCT维护子树)
- BZOJ 4530 [Bjoi2014]大融合 LCT维护子树信息
- 【LCT维护子树信息】BZOJ4530(Bjoi2014)[大融合]题解
- [BZOJ]4530 [BJOI2014] 大融合 LCT维护子树信息
- bzoj4530 [Bjoi2014]大融合(lct维护虚边信息)
- 【BZOJ4530】[Bjoi2014]大融合 LCT维护子树信息
- bzoj4530 [Bjoi2014]大融合(LCT维护子树大小)
- JZOJ 3766【BJOI2014】大融合(lct维护子树大小)
- [BZOJ4530]-大融合-LCT维护子树信息
- 【bzoj 4530】大融合(LCT维护子树信息)
- 【bzoj4530】大融合(LCT的子树维护)
- 【BZOJ3510】首都 LCT维护子树信息+启发式合并
- [bzoj4530][Bjoi2014]大融合_LCT
- BZOJ 3510: 首都 LCT维护子树信息 启发式合并