洛谷P4299传送门

题目大意:给你一颗树,边是一条一条连上去的

在连接过程中会存在询问,询问当前节点所在联通块(其实是一颗树)的重心是哪个节点

以及森林中所有树的重心的异或和

在做这道题之前,要先了解树的重心的一个性质:

两棵树合并时,新树的重心在合并后,原来两颗树的重心的两个节点构成的那条链上

了解了这条性质,思路就不难想了

当连接两个节点时,先寻找它们所在原树的重心,然后连接这两个节点,在取出两个原树重心那两个节点构成的那条链

每次寻找重心,连接节点,取出重心形成了链,复杂度约为

如果我们暴力跑这条链,最差的情况是每次合并时,两颗树都是等长的链,然后像线段树那样从下往上合并,合并次数最多是次,注意符合条件的重心最多只有2个,且子树的大小符合单调性,当越过所有重心时,及时跳出循环防止卡常

总复杂度

然而我还是喜闻乐见得被卡常了

 #include <cstdio>
#include <cstring>
#include <algorithm>
#define il inline
#define N 200100
using namespace std; int n,m,tp,num,xsum;
int stk[N],que[N]; struct LinkCutTree{
#define ls ch[x][0]
#define rs ch[x][1]
int fa[N],ch[N][],sz[N],sum[N],rv[N];
il int idf(int x){return ch[fa[x]][]==x?:;}
il void rev(int x){swap(ls,rs),rv[x]^=;}
il int isroot(int x){return (ch[fa[x]][]!=x&&ch[fa[x]][]!=x)?:;}
il void pushup(int x){sum[x]=sum[ls]+sum[rs]+sz[x]+;}
il void pushdown(int x)
{
if(rv[x]){
if(ls) rev(ls);
if(rs) rev(rs);
rv[x]^=;
}
}
il void rot(int x)
{
int y=fa[x],ff=fa[y],px=idf(x),py=idf(y);
if(!isroot(y)) ch[ff][py]=x;fa[x]=ff;
ch[y][px]=ch[x][px^],fa[ch[x][px^]]=y;
ch[x][px^]=y,fa[y]=x;
pushup(y),pushup(x);
}
void splay(int x)
{
int y=x;stk[++tp]=x;
while(!isroot(y)){stk[++tp]=fa[y],y=fa[y];}
while(tp){pushdown(stk[tp--]);}
while(!isroot(x))
{
y=fa[x];
if(isroot(y)) rot(x);
else if(idf(y)==idf(x)) rot(y),rot(x);
else rot(x),rot(x);
}
}
void access(int x){
for(int y=;x;y=x,x=fa[x])
splay(x),sz[x]-=sum[y],sz[x]+=sum[ch[x][]],ch[x][]=y,pushup(x);}
il void mkroot(int x){access(x),splay(x),rev(x);}
il void split(int x,int y){mkroot(y),access(x),splay(x);}
il int findrt(int x){
access(x),splay(x);
while(){
pushdown(x);
if(!ch[x][])break;
x=ch[x][];}
splay(x);return x;
}
void mid_dfs(int x)
{
pushdown(x);
if(ls) mid_dfs(ls);
que[++num]=x;
if(rs) mid_dfs(rs);
}
il void link(int x,int y)
{
int gx=findrt(x),gy=findrt(y);
xsum=xsum^gx^gy;
if(sum[gx]<sum[gy]) swap(x,y),swap(gx,gy);
split(x,y),fa[y]=x,sz[x]+=sum[y],pushup(x);
num=,split(gy,gx),mid_dfs(gy);
int ma=sum[gy]/,ans=0x3f3f3f3f;
for(int i=;i<=num;i++){
splay(que[i]);
if(sum[ch[que[i]][]]<=ma&&sum[ch[que[i]][]]<=ma&&que[i]<ans)
ans=que[i];
if(sum[ch[que[i]][]]>ma) break;}
mkroot(ans);
xsum^=ans;
}
#undef ls
#undef rs
}lct;
int gint()
{
int rett=,fh=;char c=getchar();
while(c<''||c>''){if(c=='-')fh=-;c=getchar();}
while(c>=''&&c<=''){rett=(rett<<)+(rett<<)+c-'';c=getchar();}
return rett*fh;
}
void gchar(char str[])
{
int p=;char c=getchar();
while(!((c>='A'&&c<='Z')||(c>='a'&&c<='z'))){c=getchar();}
while((c>='A'&&c<='Z')||(c>='a'&&c<='z')){str[p++]=c;c=getchar();}
str[p]='\0';
} int main()
{
scanf("%d%d",&n,&m);
for(int i=;i<=n;i++) xsum^=i;
char q[];int x,y;
for(int i=;i<=m;i++)
{
gchar(q);
if(q[]=='A'){
x=gint(),y=gint();
lct.link(x,y);
}else if(q[]=='Q'){
x=gint();
printf("%d\n",lct.findrt(x));
}else printf("%d\n",xsum);
}
return ;
}

BZOJ 3510 首都 (LCT)的更多相关文章

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

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

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

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

  3. BZOJ 3510 - 首都 「 $LCT$ 动态维护树的重心」

    这题 FlashHu 的优化思路值得借鉴 前置引理 树中所有点到某个点的距离和中,到重心的距离和是最小的. 把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上. 一棵树 ...

  4. 【刷题】BZOJ 3510 首都

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

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

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

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

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

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

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

  8. BZOJ 2959 长跑 (LCT+并查集)

    题面:BZOJ传送门 当成有向边做的发现过不去样例,改成无向边就忘了原来的思路.. 因为成环的点一定都能取到,我们把它们压成一个新点,权值为环上所有点的权值和 这样保证了图是一颗森林 每次询问转化为, ...

  9. BZOJ 3306: 树 LCT + set 维护子树信息

    可以作为 LCT 维护子树信息的模板,写的还是比较优美的. 本地可过,bzoj 时限太紧,一直 TLE #include<bits/stdc++.h> #define setIO(s) f ...

随机推荐

  1. 洛谷P1046 陶陶摘苹果

    题目描述 陶陶家的院子里有一棵苹果树,每到秋天树上就会结出 101010 个苹果.苹果成熟的时候,陶陶就会跑去摘苹果.陶陶有个 303030 厘米高的板凳,当她不能直接用手摘到苹果的时候,就会踩到板凳 ...

  2. Spring 使用外部属性文件配置

    1.Spring提供了一个PropertyPlaceholderConfigurer的BeanFactory后置处理器,这个处理器允许用户将Bean的配置的部分内容 移到属性文件中.可以在Bean配置 ...

  3. CNN实现terecord、数据集、模型训练

    AlexNet(Alex Krizhevsky,ILSVRC2012冠军)适合做图像分类.层自左向右.自上向下读取,关联层分为一组,高度.宽度减小,深度增加.深度增加减少网络计算量. 训练模型数据集 ...

  4. HelloWorld编译正常运行报noclassdeffounderror

    修改环境变量classpath: 原理: classpath是搜索java类库的路径:当你输入命令“java HelloWorld“时,会根据classpath寻找HelloWorld.class:一 ...

  5. PL/SQL控制语句

    本节要点: l  选择结构控制语句 if条件控制语句 Case语句 l  循环结构控制语句 基本loop循环 for循环 while循环 嵌套循环 PL/SQL既然是面向过程的编程语言,那么它就有针对 ...

  6. [SQL]选取随机行

    在sql server中语句如下: select     top 10     * from recordTable order by NEWID();

  7. POJ 3243

    Babystep算法.具体为什么,我也不太明白,好像资料不多. #include <iostream> #include <cstdio> #include <cstri ...

  8. Android仿IOS的AssistiveTouch的控件EasyTouch实现

    概述: 之前我听到过一则新闻,就是说Ipone中的AssistiveTouch的设计初衷是给残疾人使用的. 而这一功能在亚洲(中国)的使用最为频繁. 虽不知道这新闻的可靠性,但无庸置疑的是它的确给我们 ...

  9. VS2010编译器工具cl对c++11标准支持情况測试

    本文探讨了VS2010编译工具cl对C++11标准的支持情况.提供了利用C++11新特性的两段代码来进行測试,并同g++ 4.9.3编译器的编译情况相对照.总的说来:VS2010的编译器工具cl部分支 ...

  10. wpf获取目录路径

    AppDomain.CurrentDomain.BaseDirectory +文件名即可,简单吧? //获取启动了应用程序的可执行文件的路径,不包括可执行文件的名称. string str5=Appl ...