传送门

动态维护森林

显然考虑 $LCT$

但是发现询问求的是子树大小,比较不好搞

维护 $sum[x]$ 表示节点 $x$ 的子树大小,$si[x]$ 表示 $x$ 的子树中虚儿子的子树大小和

那么 $pushup$ 可以这样写:

inline void pushup(int x) { sum[x]=sum[c[x][]]+sum[c[x][]]+si[x]+; }

考虑什么时候 $si$ 会变

首先对于 $rotate,splay$ 因为都是对一条实链搞,所以对虚边没影响

然后考虑 $access$ ,发现边的虚实有改变

原本 $x$ 的右儿子变成另一个节点,那么要记得更新

然后 $makeroot$ ,发现我们翻转的是一条实链,所以同样不会对虚边产生影响

然后 $split$ ,调用了 $makeroot,access,splay$ 这些之前都考虑过了

然后 $link$,发现多了一条虚边,所以要记得更新一下

然后 $cut$,因为断的是实边,所以不会改变

那么询问时只要 $makeroot(x),access(y),splay(y)$ ,然后 $y$ 的右儿子就是 $x$ ,输出 $(si[x]+1)*(si[y]+1)$ 即可

具体看代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
int x=,f=; char ch=getchar();
while(ch<''||ch>'') { if(ch=='-') f=-; ch=getchar(); }
while(ch>=''&&ch<='') { x=(x<<)+(x<<)+(ch^); ch=getchar(); }
return x*f;
}
const int N=2e5+;
int c[N][],fa[N],si[N],sum[N];
bool rev[N];//维护的是延时标记
inline void pushup(int x) { sum[x]=sum[c[x][]]+sum[c[x][]]+si[x]+; }
inline void pushdown(int x)
{
if(!x||!rev[x]) return;
int &lc=c[x][],&rc=c[x][];
swap(lc,rc); rev[x]=;
if(lc) rev[lc]^=;
if(rc) rev[rc]^=;
}
inline void rever(int x) { rev[x]^=; pushdown(x); }
inline bool notroot(int x) { return (c[fa[x]][]==x)|(c[fa[x]][]==x); }
inline void rotate(int x)
{
int y=fa[x],z=fa[y],d=(c[y][]==x);
if(notroot(y)) c[z][c[z][]==y]=x;
fa[x]=z; fa[y]=x; fa[c[x][d^]]=y;
c[y][d]=c[x][d^]; c[x][d^]=y;
pushup(y); pushup(x);
}
void push_tag(int x)
{
if(notroot(x)) push_tag(fa[x]);
else pushdown(x);
pushdown(c[x][]); pushdown(c[x][]);
}
inline void splay(int x)
{
push_tag(x);
while(notroot(x))
{
int y=fa[x],z=fa[y];
if(notroot(y))
{
if(c[z][]==y ^ c[y][]==x) rotate(x);
else rotate(y);
}
rotate(x);
}
}
inline void access(int x)
{
for(int y=;x;y=x,x=fa[x])
{
splay(x); si[x]+=(sum[c[x][]]-sum[y]);//记得更新si
c[x][]=y; pushup(x);
}
}
inline void makeroot(int x) { access(x); splay(x); rever(x); }
inline void split(int x,int y) { makeroot(x); access(y); splay(y); }
inline void link(int x,int y) { split(x,y); fa[x]=y; si[y]+=sum[x];/*更新si*/ pushup(y); }
inline void query(int x,int y)
{
split(x,y);//和makeroot(x),access(y),splay(y)是同样的写法
printf("%lld\n",1ll*(si[x]+)*(si[y]+));
}
int n,m;
int main()
{
int a,b; char s[];
n=read(); m=read();
for(int i=;i<=n;i++) sum[i]=;
while(m--)
{
scanf("%s",s); a=read(),b=read();
if(s[]=='A') link(a,b);
else query(a,b);
}
return ;
}

P4219 [BJOI2014]大融合的更多相关文章

  1. P4219 [BJOI2014]大融合(LCT)

    P4219 [BJOI2014]大融合 对于每个询问$(u,v)$所求的是 ($u$的虚边子树大小+1)*($v$的虚边子树大小+1) 于是我们再开个$si[i]$数组表示$i$的虚边子树大小,维护一 ...

  2. 洛谷 P4219 [BJOI2014]大融合 解题报告

    P4219 [BJOI2014]大融合 题目描述 小强要在\(N\)个孤立的星球上建立起一套通信系统.这套通信系统就是连接\(N\)个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的 ...

  3. 洛谷P4219 - [BJOI2014]大融合

    Portal Description 初始有\(n(n\leq10^5)\)个孤立的点,进行\(Q(Q\leq10^5)\)次操作: 连接边\((u,v)\),保证\(u,v\)不连通. 询问有多少条 ...

  4. 洛谷P4219 [BJOI2014]大融合(LCT,Splay)

    LCT维护子树信息的思路总结与其它问题详见我的LCT总结 思路分析 动态连边,LCT题目跑不了了.然而这题又有点奇特的地方. 我们分析一下,查询操作就是要让我们求出砍断这条边后,x和y各自子树大小的乘 ...

  5. 洛谷P4219 [BJOI2014]大融合(LCT)

    LCT维护子树信息的思路总结与其它问题详见我的LCT总结 思路分析 动态连边,LCT题目跑不了了.然而这题又有点奇特的地方. 我们分析一下,查询操作就是要让我们求出砍断这条边后,x和y各自子树大小的乘 ...

  6. P4219 [BJOI2014]大融合 LCT维护子树大小

    \(\color{#0066ff}{ 题目描述 }\) 小强要在\(N\)个孤立的星球上建立起一套通信系统.这套通信系统就是连接\(N\)个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一 ...

  7. 洛谷 P4219 [BJOI2014]大融合

    查询,就相当于先删去这条边,然后查询边的两个端点所在连通块大小,乘起来得到答案,然后再把边加回去 可以用线段树分治做 #pragma GCC optimize("Ofast") # ...

  8. luogu P4219 [BJOI2014]大融合

    题解:原来LCT也能维护子树信息,我太Naive了 用LCT维护当前子树节点个数 具体做法维护siz[x]=当前Splay子树和指向当前Splay子树的虚边所代表的节点个数 auxsiz[x]=指向x ...

  9. [BZOJ4530][Bjoi2014]大融合 LCT + 启发式合并

    [BZOJ4530][Bjoi2014]大融合 试题描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是 ...

随机推荐

  1. id 和 instancetype 方法的区别

    首先明确 id 和 instancetype 都是万能指针,都能指向一个对象:(instancetype == id == 万能指针 == 指向一个对象) 主要区别亮点: 1. id 在编译时候不能判 ...

  2. javascript使用技巧总结,不断更新...

    1.使用a标签来获得当前页面相对地址的绝对地址 function getAbsoluteUrl(url){ var a; if(!a) a = document.createElement('a'); ...

  3. Angular23 loading组件、路由配置、子路由配置、路由懒加载配置

    1 需求 由于Angular是单页面的应用,所以在进行数据刷新是进行的局部刷新:在进行数据刷新时从浏览器发出请求到后台响应数据是有时间延迟的,所以在这段时间就需要进行遮罩处理来提示用户系统正在请求数据 ...

  4. 10个强大的Javascript表单验证插件推荐

    创建一个JavaScript表单验证插件,可以说是一个繁琐的过程,涉及到初期设计.开发与测试等等环节.实际上一个优秀的程序员不仅是技术高手,也应该是善假于外物的.本文介绍了10个不错的JavaScri ...

  5. jQuery基础教程-第8章-002Adding jQuery object methods

    一.Object method context 1.We have seen that adding global functions requires extending the jQuery ob ...

  6. JavaEE互联网轻量级框架整合开发(书籍)阅读笔记(3):常用动态代理之JDK动态代理、CGLIB动态代理

    一.动态代理的理解 动态代理的意义在于生成一个占位(又称代理对象),来代理真实对象,从而控制真实对象的访问.        先来谈谈什么是代理模式.        假设这样一个场景:你的公司是一家软件 ...

  7. 查询某张表被哪些存储过程或者视图用到的sql语句

    /*查询某张表被哪些存储过程或者视图用到的sql语句*/select distinct object_name(id) from syscomments where id in (select id ...

  8. C# Excel 操作

    Excel数据到datagridview 里面 (流读取) System.Windows.Forms.OpenFileDialog fd = new OpenFileDialog(); if (fd. ...

  9. C#Task学习

    简介: Task 对象是一种的中心思想基于任务的异步模式首次引入.NET Framework 4 中. 因为由执行工作Task对象通常以异步方式执行线程池线程上而不是以同步方式在主应用程序线程中,可以 ...

  10. .NET平台的资源文件管理

    可以管理文本.图片等不同类型的资源 管理方式(增删改) 可以直接修改XXX.resx源文件(XML格式,文本直接管理内容,图片需要指定路径,资源名和图片名可以不同) 也可以在VS的可视化界面上进行操作 ...