博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【BZOJ4530】[Bjoi2014]大融合 LCT维护子树信息
阅读量:4313 次
发布时间:2019-06-06

本文共 2428 字,大约阅读时间需要 8 分钟。

【BZOJ4530】[Bjoi2014]大融合

Description

小强要在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)。
现在,你的任务就是随着边的添加,动态的回答小强对于某些边的负载的询问。

Input

第一行包含两个整数N,Q,表示星球的数量和操作的数量。星球从1开始编号。
接下来的Q行,每行是如下两种格式之一:
A x y 表示在x和y之间连一条边。保证之前x和y是不联通的。
Q x y 表示询问(x,y)这条边上的负载。保证x和y之间有一条边。
1≤N,Q≤100000

Output

对每个查询操作,输出被查询的边的负载。

Sample Input

8 6
A 2 3
A 3 4
A 3 8
A 8 7
A 6 5
Q 3 8

Sample Output

6

题解:网上看到好多并查集+线段树合并,感觉想法很好,但是还是去学了一发姜神的LCT。

用LCT维护子树信息,维护LCT中一个点的所有儿子的信息以及所有虚儿子的信息。因为当我们对x进行access+splay操作后,原树中x的父亲全在splay中x的左子树里,并且x没有右子树,所以x的儿子都在x的虚子树中。那么如何维护虚子树的信息呢?

发现,虚子树的信息只有在access和link时会变化,在access时,原来的右儿子变虚,又新来了一个右儿子,所以虚子树的信息要加上原来的右儿子,减去新加的右儿子。在link时,y新加了虚儿子x,那么y要加上x的信息。并且注意,为了不影响其他的点,需要对y也进行access+splay操作。至于所有实+虚儿子的信息,直接pushup就行了。

答案就是:将y变成根,对x进行access+splay,然后ans=(y的子树信息-x的虚子树信息-1)*(x的虚子树信息+1)

 

#include 
#include
#include
using namespace std;const int maxn=100010;struct LCT{ int rev[maxn],sx[maxn],sl[maxn],ch[maxn][2],fa[maxn]; bool isr(int x) {return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} void pushup(int x) {sl[x]=sx[x]+sl[ch[x][0]]+sl[ch[x][1]]+1;} void pushdown(int x) { if(rev[x]) { swap(ch[x][0],ch[x][1]); if(ch[x][0]) rev[ch[x][0]]^=1; if(ch[x][1]) rev[ch[x][1]]^=1; rev[x]=0; } } void updata(int x) { if(!isr(x)) updata(fa[x]); pushdown(x); } void rotate(int x) { int y=fa[x],z=fa[y],d=(x==ch[y][1]); if(!isr(y)) ch[z][y==ch[z][1]]=x; fa[x]=z,fa[y]=x,ch[y][d]=ch[x][d^1]; if(ch[x][d^1]) fa[ch[x][d^1]]=y; ch[x][d^1]=y; pushup(y),pushup(x); } void splay(int x) { updata(x); while(!isr(x)) { int y=fa[x],z=fa[y]; if(!isr(y)) { if((x==fa[y])^(z==fa[y])) rotate(x); else rotate(y); } rotate(x); } } void access(int x) { for(int y=0;x;splay(x),sx[x]+=sl[ch[x][1]],ch[x][1]=y,sx[x]-=sl[y],pushup(x),y=x,x=fa[x]); } void maker(int x) { access(x),splay(x),rev[x]^=1; } void link(int x,int y) { maker(x),access(y),splay(y); sx[y]+=sl[x],fa[x]=y,pushup(y); }}tr;int n,m;char str[5];int main(){ int i,a,b; scanf("%d%d",&n,&m); for(i=1;i<=n;i++) tr.sl[i]=1; for(i=1;i<=m;i++) { scanf("%s%d%d",str,&a,&b); if(str[0]=='A') tr.link(a,b); else { tr.maker(b),tr.access(a),tr.splay(a); printf("%lld\n",(long long)(tr.sl[a]-tr.sx[b]-1)*(tr.sx[b]+1)); } } return 0;}

 

转载于:https://www.cnblogs.com/CQzhangyu/p/7061181.html

你可能感兴趣的文章
不要去管浏览器兼容
查看>>
事件冒泡 事件捕获 事件委托 W3C事件流
查看>>
Response.AddHeader
查看>>
[转]A星寻路算法
查看>>
centos 安装 rabbitMQ
查看>>
16-----margin的用法
查看>>
18-----超链接导航栏案例
查看>>
POJ 1679 The Unique MST(次小生成树)
查看>>
System.Transaction (TransactionScope) 与 可提升 (Promotable) 交易
查看>>
arcgis js api 本地化配置
查看>>
PHP学习:数组
查看>>
想爱容易,相处难:当ASP.NET MVC爱上IoC
查看>>
技术资料整理
查看>>
Ember——传数据——代码示例
查看>>
OpenStack的容器服务体验
查看>>
在创业公司做架构师,你需要解决哪些问题?
查看>>
《深入浅出pig系列之中的一个》pig-0.12.0-cdh5.1.2的安装与执行
查看>>
cocos2dx 3.1从零学习(二)——菜单、场景切换、场景传值
查看>>
百度编辑器动态添加内容及防止过滤样式或其他属性解决办法
查看>>
作业二(1)
查看>>