传送门

动态维护森林

显然考虑 $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. solr开发之基本操作

    package zr.com.util; import java.io.IOException; import java.util.List; import java.util.Map; import ...

  2. opennebula image单个实例响应数据格式

    { ", ", ", "TEMPLATE": { "DEV_PREFIX": "hd", " }, ...

  3. linux安装JDK后发现系统带有openjdk的处理

    1.JDK下载. 官网下载网址:https://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html ...

  4. getchar() getch() getche() gets() puts() scanf()的用法及区别

    getchar() putchar(ch) scanf()   头文件stdio.h getch() getche()   头文件conio.h gets() puts()    头文件stdio.h ...

  5. (转)菜鸟去重复之Sql

    原文地址:http://www.cnblogs.com/fatbird/p/Sql-Remove-duplicate.html 前言 本文主要是总结平时工作学习中遇到的使用Sql Server的去除重 ...

  6. git手动解决内容冲突

    <span style="font-size:18px;">git checkout -b lab4 origin/lab4 git merge lab3</sp ...

  7. .net Stream篇(七)

    NetworkStream 目录: NetworkStream的作用 简单介绍下TCP/IP 协议和相关层次 简单说明下 TCP和UDP的区别 简单介绍下套接字(Socket)的概念 简单介绍下Tcp ...

  8. Boost 安装详解

    一 Linux(redhat)篇 1.1 获取boost库 解压tar -zxvf boost_1.48.0.tar.gz 进入解压目录cd boost_1_48_0 1.2 编译安装 使用下面的命令 ...

  9. Java 文件上传至leanCloud

    首先,在Controller端入参设置为 @RequestParam(value = "file",defaultValue = "") MultipartFi ...

  10. Android SDK下载和更新慢或失败的解决办法

    下载完Android SDK后发现无法更新,原因是我们被墙了,所以需要使用代理来更新,或者直接把dl-ssl.google.com解析的IP改一下就可以了 用文本编辑器打开文件C:\Windows\S ...