有些题目,在要求支持link-cut之外,还会在线询问某个子树的信息。LCT可以通过维护虚边信息完成这个操作。

对于LCT上每个节点,维护两个两sz和si,后者维护该点所有虚儿子的信息,前者维护该点的所有信息和。

那么显然有:$si[x]=\sum sz[pson]$,$sz[x]=sz[lson]+sz[rson]+si[x]+v[x]$。

其中pson是虚儿子,lson,rson是LCT上的实儿子,v是节点本身的信息。

那么,考虑在哪些操作下需要更新这两个值。

1.access  每次将旧虚儿子从si中减去,加入新虚儿子的贡献。

2.link f[x]=y后,将x的信息计入si[y]。

别的操作要注意pushup。

这样我们维护了sz和si这两个变量,当想查询y的子树的信息和的时候,只需access(y),splay(y)后查询si[y]即可。

[BZOJ4530][BJOI2014]大融合

n个点,n-1次加边,最后形成一棵树。加边过程中会询问某条边现在被多少对点(x,y)之间的路径经过。

显然是link的过程中查询子树大小,最后询问的就是(整个连通块的大小-x子树的大小)*(x子树的大小)。

按上面的方法维护子树大小即可。

 #include<cstdio>
#include<algorithm>
#define lc ch[x][0]
#define rc ch[x][1]
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
char op;
int n,Q,u,v,sz[N],f[N],ch[N][],rev[N],si[N]; bool isrt(int x){ return (!f[x]) || (ch[f[x]][]!=x && ch[f[x]][]!=x); }
void upd(int x){ sz[x]=sz[lc]+sz[rc]+si[x]+; }
void put(int x){ swap(lc,rc); rev[x]^=; }
void push(int x){ if (rev[x]) put(lc),put(rc),rev[x]=; }
void pd(int x){ if (!isrt(x)) pd(f[x]); push(x); } void rot(int x){
int y=f[x],z=f[y],w=ch[y][]==x;
if (!isrt(y)) ch[z][ch[z][]==y]=x;
f[x]=z; f[y]=x; f[ch[x][w^]]=y;
ch[y][w]=ch[x][w^]; ch[x][w^]=y; upd(y);
} void splay(int x){
pd(x);
while (!isrt(x)){
int y=f[x],z=f[y];
if (!isrt(y)) (ch[y][]==x)^(ch[z][]==y) ? rot(x) : rot(y);
rot(x);
}
upd(x);
} void access(int x){
for (int y=; x; y=x,x=f[x])
splay(x),si[x]=si[x]+sz[rc]-sz[y],rc=y,upd(x);
} void mkrt(int x){ access(x); splay(x); put(x); } void link(int x,int y){
mkrt(x); access(y); splay(y);
f[x]=y; si[y]+=sz[x]; upd(y);
} ll que(int x,int y){ mkrt(x); access(y); splay(y); return 1ll*(sz[y]-sz[x])*sz[x]; } int main(){
scanf("%d%d",&n,&Q);
rep(i,,n) sz[i]=;
while (Q--){
scanf(" %c%d%d",&op,&u,&v);
if (op=='A') link(u,v); else printf("%lld\n",que(u,v));
}
return ;
}

[BZOJ3510]首都

link的同时询问某个连通块的重心,以及所有连通块重心编号的异或和。

仍然考虑用LCT维护子树大小。每次link两个连通块时,先作普通的link操作,然后求出新的连通块的重心。

显然新重心一定在原来两个连通块重心的连线上,split出这条链后在链上二分。

用ls,rs分别维护这条链两端已被二分排除的部分的大小,每次如果发现当前点合法则更新答案,否则往大的子树那边跳。

记得pushdown。多splay以保证复杂度。

 #include<cstdio>
#include<algorithm>
#define lc ch[x][0]
#define rc ch[x][1]
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
char op[];
int n,Q,ans,x,y,sz[N],fa[N],f[N],ch[N][],rev[N],si[N]; int get(int x){ return fa[x]==x ? x : fa[x]=get(fa[x]); }
bool isrt(int x){ return (!f[x]) || (ch[f[x]][]!=x && ch[f[x]][]!=x); }
void upd(int x){ sz[x]=sz[lc]+sz[rc]+si[x]+; }
void put(int x){ swap(lc,rc); rev[x]^=; }
void push(int x){ if (rev[x]) put(lc),put(rc),rev[x]=; }
void pd(int x){ if (!isrt(x)) pd(f[x]); push(x); } void rot(int x){
int y=f[x],z=f[y],w=ch[y][]==x;
if (!isrt(y)) ch[z][ch[z][]==y]=x;
f[x]=z; f[y]=x; f[ch[x][w^]]=y;
ch[y][w]=ch[x][w^]; ch[x][w^]=y; upd(y);
} void splay(int x){
pd(x);
while (!isrt(x)){
int y=f[x],z=f[y];
if (!isrt(y)) (ch[y][]==x)^(ch[z][]==y) ? rot(x) : rot(y);
rot(x);
}
upd(x);
} void access(int x){
for (int y=; x; y=x,x=f[x])
splay(x),si[x]=si[x]+sz[rc]-sz[y],rc=y,upd(x);
} void mkrt(int x){ access(x); splay(x); put(x); } void split(int x,int y){ mkrt(x); access(y); splay(y); } void link(int x,int y){
mkrt(x); mkrt(y); f[x]=y; si[y]+=sz[x]; upd(y);
x=get(x); y=get(y); split(x,y);
int s=n+,now=y,ls=,rs=,lim=sz[y]/;
while (now){
push(now); int s1=ls+sz[ch[now][]],s2=rs+sz[ch[now][]];
if (s1<=lim && s2<=lim) s=min(s,now);
if (s1>s2) rs+=sz[ch[now][]]+si[now]+,now=ch[now][];
else ls+=sz[ch[now][]]+si[now]+,now=ch[now][];
}
splay(s); fa[x]=fa[y]=fa[s]=s; ans=ans^x^y^s;
} int main(){
scanf("%d%d",&n,&Q);
rep(i,,n) ans^=i,sz[i]=,fa[i]=i;
while (Q--){
scanf("%s",op);
if (op[]=='X') printf("%d\n",ans);
else if (op[]=='Q') scanf("%d",&x),printf("%d\n",get(x));
else scanf("%d%d",&x,&y),link(x,y);
}
return ;
}

[UOJ#207]共价大爷游长沙

支持:往询问集合中添加删除路径,link-cut,询问某条边是否被集合中的所有路径经过。

一个显然的结论是,一条边(x,y)被所有路径经过,当且仅当整棵树以x为根时,所有路径恰有一个端点在y子树内。

于是我们将所有路径的两端都加上一个随机权值(不同路径用不同权值,同一路径两端用同一个权值),再询问y子树内所有点的权值异或和。

若等于所有路径随机权值的异或和则说明所有路径均恰有一端点在子树内。

随机种子要带时间戳否则会被Hack数据卡掉。

 #include<cstdio>
#include<ctime>
#include<algorithm>
#define lc ch[x][0]
#define rc ch[x][1]
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
typedef long long ll;
using namespace std; const int N=;
int op;
int n,Q,ans,x,y,tot,sz[N],fa[N],f[N],ch[N][],rev[N],si[N],w[N*],tx[N*],ty[N*]; int Rand(){ return (rand()<<)+rand(); }
int get(int x){ return fa[x]==x ? x : fa[x]=get(fa[x]); }
bool isrt(int x){ return (!f[x]) || (ch[f[x]][]!=x && ch[f[x]][]!=x); }
void upd(int x){ sz[x]=sz[lc]^sz[rc]^si[x]; }
void put(int x){ swap(lc,rc); rev[x]^=; }
void push(int x){ if (rev[x]) put(lc),put(rc),rev[x]=; }
void pd(int x){ if (!isrt(x)) pd(f[x]); push(x); } void rot(int x){
int y=f[x],z=f[y],w=ch[y][]==x;
if (!isrt(y)) ch[z][ch[z][]==y]=x;
f[x]=z; f[y]=x; f[ch[x][w^]]=y;
ch[y][w]=ch[x][w^]; ch[x][w^]=y; upd(y);
} void splay(int x){
pd(x);
while (!isrt(x)){
int y=f[x],z=f[y];
if (!isrt(y)) (ch[y][]==x)^(ch[z][]==y) ? rot(x) : rot(y);
rot(x);
}
upd(x);
} void access(int x){
for (int y=; x; y=x,x=f[x])
splay(x),si[x]=si[x]^sz[rc]^sz[y],rc=y,upd(x);
} void mkrt(int x){ access(x); splay(x); put(x); }
void split(int x,int y){ mkrt(x); access(y); splay(y); }
void link(int x,int y){ mkrt(x); access(y); splay(y); f[x]=y; si[y]^=sz[x]; }
void cut(int x,int y){ split(x,y); f[x]=ch[y][]=; upd(y); }
void add(int x,int k){ mkrt(x); sz[x]^=k; si[x]^=k; } int main(){
srand(time(NULL));
scanf("%*d%d%d",&n,&Q);
rep(i,,n) scanf("%d%d",&x,&y),link(x,y);
while (Q--){
scanf("%d",&op);
if (op==) scanf("%d%d",&x,&y),cut(x,y),scanf("%d%d",&x,&y),link(x,y);
if (op==){
tot++; scanf("%d%d",&tx[tot],&ty[tot]); w[tot]=Rand();
ans^=w[tot]; add(tx[tot],w[tot]); add(ty[tot],w[tot]);
}
if (op==) scanf("%d",&x),ans^=w[x],add(tx[x],w[x]),add(ty[x],w[x]);
if (op==) scanf("%d%d",&x,&y),split(x,y),puts((si[y]==ans)?"YES":"NO");
}
return ;
}

LCT维护子树信息的更多相关文章

  1. 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息

    题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量 ...

  2. 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息

    题目描述 给出一棵树和一个点对集合S,多次改变这棵树的形态.在集合中加入或删除点对,或询问集合内的每组点对之间的路径是否都经过某条给定边. 输入 输入的第一行包含一个整数 id,表示测试数据编号,如第 ...

  3. 【bzoj3510】首都 LCT维护子树信息(+启发式合并)

    题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...

  4. 【BZOJ3510】首都 LCT维护子树信息+启发式合并

    [BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打 ...

  5. 共价大爷游长沙 lct 维护子树信息

    这个题目的关键就是判断 大爷所有可能会走的路 会不会经过询问的边. 某一条路径经过其中的一条边, 那么2个端点是在这条边的2测的. 现在我们要判断所有的路径是不是都经过 u -> v 我们以u为 ...

  6. bzoj3510 首都 LCT 维护子树信息+树的重心

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删 ...

  7. $LCT$维护子树信息学习笔记

    \(LCT\)维护子树信息学习笔记 昨天\(FDF\)好题分享投了 \([ZJOI2018]\)历史 这题. 然后我顺势学学这个姿势. 结果调了一年...于是写个笔记记录一下. 基本原理 比较显然地, ...

  8. 【LCT维护子树信息】uoj207 共价大爷游长沙

    这道题思路方面就不多讲了,主要是通过这题学一下lct维护子树信息. lct某节点u的子树信息由其重链的一棵splay上信息和若干轻儿子子树信息合并而成. splay是有子树结构的,可以在rotate, ...

  9. 洛谷4219 BJOI2014大融合(LCT维护子树信息)

    QWQ 这个题目是LCT维护子树信息的经典应用 根据题目信息来看,对于一个这条边的两个端点各自的\(size\)乘起来,不过这个应该算呢? 我们可以考虑在LCT上多维护一个\(xv[i]\)表示\(i ...

  10. BZOJ4530[Bjoi2014]大融合——LCT维护子树信息

    题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够 联通的树上路过它的简单路径的数 ...

随机推荐

  1. layui-laypage模块代码详解

    /** layui-v2.4.0 MIT License By https://www.layui.com */;layui.define(function(e) { "use strict ...

  2. Go语言的各种Print函数

    Go语言的各种Print函数 func Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) func Pr ...

  3. console.dir() 与 console.dirxml() 的使用

    在调试JavaScript程序时,有时需要dump某些对象的详细信息.通过手工编写JavaScript代码可以完成这一工作:针对对象的属性进行循环,将循环到的每一个属性值打印出来:可见,这一过程是比较 ...

  4. python学习笔记之split()方法与with

    Python split()方法 以下内容摘自:http://www.runoob.com/python/att-string-split.html 描述 Python split()通过指定分隔符对 ...

  5. 【转】Spring MVC 标签总结

    1.@Controller 在SpringMVC 中,控制器Controller 负责处理由DispatcherServlet 分发的请求,它把用户请求的数据经过业务处理层处理之后封装成一个Model ...

  6. 打包egg

    scrapyd-deploy -p chahao -v 1.0 --build-egg chahao.egg

  7. MongoDB安全:所有操作(Privilege Actions)

    本文展示了两张思维导图,分别是MongoDB 3.6.4.0的所有权限操作,未做深入研究,仅仅是列出来. 3.6总共9类105个操作,4.0版本比3.6多了两类操作,同时增加了3个操作,共11类108 ...

  8. python网络编程-同步IO和异步IO,阻塞IO和非阻塞IO

    同步IO和异步IO,阻塞IO和非阻塞IO分别是什么,到底有什么区别?不同的人在不同的上下文下给出的答案是不同的.所以先限定一下本文的上下文. 本文讨论的背景是Linux环境下的network IO. ...

  9. Python字符串(Str)详解

    字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可 字符串的格式 b = "hello itcast. ...

  10. 用HTML+CSS实现--折叠效果

    下图是一个Accordion组件,请用HTML+CSS实现其UI,并用面向对象的思路把折叠效果JS实现.如果能用纯css的方式实现其折叠效果更佳.PS/这是小米15年的一道校招笔试题,无意间看到就实现 ...