既然是中文题目,这里便不给题意。

分析:

  这个题的做法据说是启发式合并?

  但是我不会啊……

  进入正题,LCT是怎样做掉这道题的。记得在前面的一篇《大融合》的题解中,介绍过LCT维护子树信息的做法。

  一句话概括就是要维护虚子树和实子树的size,适时修改,保持其正确性。

  这道题关键并不在这,但我们必须要维护这样一个信息才可以做。

  很简单很直观的一个想法,因为我们每次合并两棵树时,新的重心必然出现在原来两个重心的路径上。

  这是为什么?我们假设如果不在这条路径上,而是其中一棵树的其他子树的某一点,那么我们发现这一点比起之前,size较大的一棵子树上又缀了一棵树(以这个点为根),所以一定不优。

  于是我们就合并树后把两棵原树的重心打通,(放到一个splay里),这时候尺寸就派上用场了,我们就在这个splay里查找,因为重心反正肯定存在于这个splay中了,那么我们就维护一个左尺寸,一个右尺寸。左边大了我们就让重心往左移动,右边大了就往右移动,直到两边的尺寸都小于等于总尺寸的一半,就好啦!(别忘了多个重心时的编号最小化)

代码:

 #include<bits/stdc++.h>
#define lc(x) t[x][0]
#define rc(x) t[x][1]
using namespace std;
const int N=;
const int inf=0x3f3f3f3f;
struct LCT{
int t[N][],s[N],rev[N],fa[N],sx[N],sz[N],tp;
void pushup(int x){
sz[x]=sz[lc(x)]+sz[rc(x)]+sx[x]+;
} bool pdrt(int x){
return rc(fa[x])!=x&&lc(fa[x])!=x;
} void revers(int x){
rev[x]^=;swap(lc(x),rc(x));
} void pushdown(int x){
if(rev[x]){ rev[x]=;
if(lc(x)) revers(lc(x));
if(rc(x)) revers(rc(x));
} return ;
} void rotate(int x){
int y=fa[x];int z=fa[y];
int dy=(rc(y)==x),dz=(rc(z)==y);
if(!pdrt(y)) t[z][dz]=x;
t[y][dy]=t[x][dy^];fa[t[y][dy]]=y;
t[x][dy^]=y;fa[y]=x;fa[x]=z;
pushup(y);return ;
} void splay(int x){
s[++tp]=x;
for(int i=x;!pdrt(i);i=fa[i])
s[++tp]=fa[i];
while(tp) pushdown(s[tp--]);
while(!pdrt(x)){
int y=fa[x];int z=fa[y];
if(!pdrt(y))
if(rc(y)==x^rc(z)==y) rotate(x);
else rotate(y);rotate(x);
} pushup(x);return ;
} void access(int x){
for(int i=;x;x=fa[i=x])
splay(x),sx[x]+=sz[rc(x)],
sx[x]-=sz[rc(x)=i],pushup(x);
} void mkrt(int x){
access(x);splay(x);revers(x);
} void split(int x,int y){
mkrt(x);access(y);splay(y);
} void link(int x,int y){
split(x,y);sx[fa[x]=y]+=sz[x];
pushup(y);
} int update(int x){
int l,r,o=sz[x]&,sm=sz[x]>>,
ls=,rs=,np=inf,nl,nr;
while(x){
pushdown(x);
nl=sz[l=lc(x)]+ls;nr=sz[r=rc(x)]+rs;
if(nl<=sm&&nr<=sm){
if(o){np=x;break;}
else if(np>x) np=x;
} if(nl<nr) ls+=sz[l]+sx[x]+,x=r;
else rs+=sz[r]+sx[x]+,x=l;
} splay(np);return np;
}
}t;int n,m,fa[N];
int get(int x){
return fa[x]==x?x:fa[x]=get(fa[x]);
} int main(){
char c[];int rox=;//尤为重要,必须赋0;
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++)
t.sz[i]=,fa[i]=i,rox^=i;
while(m--){
scanf("%s",c);int x,y,z;
if(c[]=='A'){
scanf("%d%d",&x,&y);t.link(x,y);
t.split(x=get(x),y=get(y));
z=t.update(y);rox=(rox^x^y^z);
fa[x]=fa[y]=fa[z]=z;
} else if(c[]=='Q'){
scanf("%d",&x);
printf("%d\n",get(x));
} else printf("%d\n",rox);
} return ;
}

Luogu P4299 首都 LCT的更多相关文章

  1. luogu P4299 首都

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

  2. P4299 首都

    题目 P4299 首都 做法 这题是动态维护树的重心,连边后找到两棵树的重心拉一条链(性质:新重心在链上),然后暴力爬 要注意: 1.是找重心的过程中要先把旋转标记放下来,因为\(Splay(x)\) ...

  3. 洛谷P4299 首都(BZOJ3510)(LCT,树的重心,二分查找)

    Update:原来的洛谷U21715已成坑qwq 已经被某位管理员巨佬放进公共题库啦!又可以多一个AC记录啦! 洛谷题目传送门 其实也可以到这里交啦 思路分析 动态维护树的重心 题目中说到国家的首都会 ...

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

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

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

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

  6. BZOJ 3510 首都 (LCT)

    洛谷P4299传送门 题目大意:给你一颗树,边是一条一条连上去的 在连接过程中会存在询问,询问当前节点所在联通块(其实是一颗树)的重心是哪个节点 以及森林中所有树的重心的异或和 在做这道题之前,要先了 ...

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

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

  8. BZOJ.3510.首都(LCT 启发式合并 树的重心)

    题目链接 BZOJ 洛谷 详见这. 求所有点到某个点距离和最短,即求树的重心.考虑如何动态维护. 两棵子树合并后的重心一定在两棵树的重心之间那条链上,所以在合并的时候用启发式合并,每合并一个点检查sz ...

  9. BZOJ 3510: 首都 LCT + multiset维护子树信息 + 树的重心

    Code: #include<bits/stdc++.h> #define maxn 200000 #define inf 1000000000 using namespace std; ...

随机推荐

  1. Create

    BOOL Create(LPCTSTR lpszClassName,LPCTSTR lpszWindowName, DWORD dwStyle,const RECT& rect,CWnd* p ...

  2. MHA高可用 MHA+Keepalive

    MHA高可用 MHA简介 MHA(Master High Availability)目前在MySQL高可用方面是一个相对成熟的解决方案,它由日本DeNA公司youshimaton(现就职于Facebo ...

  3. ThinkPHP3.2.3学习笔记3---视图

    一.说明 每个模块的模板文件是独立的,为了对模板文件更加有效的管理,ThinkPHP对模板文件进行目录划分,默认的模板文件定义规则是:视图目录/[模板主题/]控制器名/操作名+模板后缀 默认的视图目录 ...

  4. bzoj 1640||1692: [Usaco2007 Dec]队列变换【后缀数组】

    注意输出是80字符个一行!! 首先贪心很显然,就是两头尽量拿小的. 然后需要处理两头一样的情况,显然是选字典序小的一串,把数组反着接在原数组后面,然后跑sa,判断的时候直接比较rk数组 #includ ...

  5. java启动参数一

    java启动参数共分为三类: 其一是标准参数(-),所有的JVM实现都必须实现这些参数的功能,而且向后兼容: 其二是非标准参数(-X),默认jvm实现这些参数的功能,但是并不保证所有jvm实现都满足, ...

  6. [转]广义正交匹配追踪(gOMP)

    广义正交匹配追踪(Generalized OMP, gOMP)算法可以看作为OMP算法的一种推广,由文献[1]提出,第1作者本硕为哈工大毕业,发表此论文时在Korea University攻读博士学位 ...

  7. _bzoj3224 Tyvj 1728 普通平衡树【Splay】

    传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3224 保存splay模版 一刻不停写了一个小时多一点,幸好一遍过了!(其实带着freopen ...

  8. Rooks LightOJ - 1005

    https://vjudge.net/problem/LightOJ-1005 题意:在n*n的矩形上放k个车,使得它们不能互相攻击,求方案数. ans[i][j]表示在i*i的矩形上放j个车的方案数 ...

  9. C#扩展方法学习

    扩展方法的本质是什么,详细见此文 C#扩展方法,爱你在心口难开 重点如下:扩展方法使您能够向现有类型“添加”方法,而无需创建新的派生类型.重新编译或以其他方式修改原始类型.扩展方法是一种特殊的静态方法 ...

  10. 关于tomcat一些简介

    window下,在tomcat的bin目录下,用cmd输入startup.bat 即可启动tomcat 成功启动Tomcat后,通过访问http://localhost:8080/便可以使用Tomca ...