LCT维护子树信息
有些题目,在要求支持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维护子树信息的更多相关文章
- 【bzoj4530】[Bjoi2014]大融合 LCT维护子树信息
题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够联通的树上路过它的简单路径的数量 ...
- 【uoj#207】共价大爷游长沙 随机化+LCT维护子树信息
题目描述 给出一棵树和一个点对集合S,多次改变这棵树的形态.在集合中加入或删除点对,或询问集合内的每组点对之间的路径是否都经过某条给定边. 输入 输入的第一行包含一个整数 id,表示测试数据编号,如第 ...
- 【bzoj3510】首都 LCT维护子树信息(+启发式合并)
题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...
- 【BZOJ3510】首都 LCT维护子树信息+启发式合并
[BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打 ...
- 共价大爷游长沙 lct 维护子树信息
这个题目的关键就是判断 大爷所有可能会走的路 会不会经过询问的边. 某一条路径经过其中的一条边, 那么2个端点是在这条边的2测的. 现在我们要判断所有的路径是不是都经过 u -> v 我们以u为 ...
- bzoj3510 首都 LCT 维护子树信息+树的重心
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删 ...
- $LCT$维护子树信息学习笔记
\(LCT\)维护子树信息学习笔记 昨天\(FDF\)好题分享投了 \([ZJOI2018]\)历史 这题. 然后我顺势学学这个姿势. 结果调了一年...于是写个笔记记录一下. 基本原理 比较显然地, ...
- 【LCT维护子树信息】uoj207 共价大爷游长沙
这道题思路方面就不多讲了,主要是通过这题学一下lct维护子树信息. lct某节点u的子树信息由其重链的一棵splay上信息和若干轻儿子子树信息合并而成. splay是有子树结构的,可以在rotate, ...
- 洛谷4219 BJOI2014大融合(LCT维护子树信息)
QWQ 这个题目是LCT维护子树信息的经典应用 根据题目信息来看,对于一个这条边的两个端点各自的\(size\)乘起来,不过这个应该算呢? 我们可以考虑在LCT上多维护一个\(xv[i]\)表示\(i ...
- BZOJ4530[Bjoi2014]大融合——LCT维护子树信息
题目描述 小强要在N个孤立的星球上建立起一套通信系统.这套通信系统就是连接N个点的一个树. 这个树的边是一条一条添加上去的.在某个时刻,一条边的负载就是它所在的当前能够 联通的树上路过它的简单路径的数 ...
随机推荐
- APScheduler API -- apscheduler.triggers.cron
apscheduler.triggers.cron API Trigger alias for add_job(): cron class apscheduler.triggers.cron.Cron ...
- Vim 快捷键整理【转】
转自:http://blog.csdn.net/ceven2010/article/details/7406341 一.移动光标 1.左移h.右移l.下移j.上移k 2.向下翻页ctrl + f,向上 ...
- 【Android开发日记】之入门篇(十二)——Android组件间的数据传输
组件我们有了,那么我们缺少一个组件之间传递信息的渠道.利用Intent做载体,这是一个王道的做法.还有呢,可以利用文件系统来做数据共享.也可以使用Application设置全局数据,利用组件来进行控制 ...
- 洛谷P2886牛继电器
传送门啦 倍增 $ Floyd $ 注意结构体里二维数组不能开到 $ 2000 $ #include <iostream> #include <cstdio> #include ...
- HDU 2874 Connections between cities(LCA(离线、在线)求树上距离+森林)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2874 题目大意:给出n个点,m条边,q个询问,每次询问(u,v)的最短距离,若(u,v)不连通即不在同 ...
- Tomcat底层实现
package myserver; import java.io.IOException;import java.net.ServerSocket;import java.net.Socket; pu ...
- sqlserver中的全局变量总结
@@CONNECTIONS返回自上次启动 Microsoft? SQL Server? 以来连接或试图连接的次数.@@CPU_BUSY返回自上次启动 Microsoft? SQL Server? 以来 ...
- ssh连接报错Write failed: Broken pipe Resource temporarily unavailable
问题描述 使用root连接服务器正常,切换普通用户连接报错 具体报错如下:Write failed: Broken pipe 或者:failed to execute /bin/bash: Resou ...
- C语言:奇偶归一猜想
1.奇偶归一猜想——求多少步归一.(10分) 题目内容: 奇偶归一猜想——对于每一个正整数,如果它是奇数,则对它乘3再加1,如果它是偶数,则对它除以2,如此循环,最终都能够得到1. 如n = 11,得 ...
- ASP.NET MVC之Ajax如影随行
一.Ajax的前世今生 我一直觉得google是一家牛逼的公司,为什么这样说呢?<舌尖上的中国>大家都看了,那些美食估计你是百看不厌,但是里边我觉得其实也有这样的一个哲学:关于食材,对于种 ...