洛谷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. position:fixed div如何居中

    div{position:fixed;margin:auto;left:0; right:0; top:0; bottom:0;width:200px; height:150px;}

  2. 【hiho一下 第十周】后序遍历

    [题目链接]:http://hihocoder.com/problemset/problem/1049 [题意] [题解] 前序遍历的第一个节点; 肯定是整颗树的头结点; 然后在中序遍历中; 得到这个 ...

  3. ES scroll(ES游标) 解决深分页

    ES scroll(ES游标) 解决深分页. Why 当Elasticsearch响应请求时,它必须确定docs的顺序,排列响应结果.如果请求的页数较少(假设每页20个docs), Elasticse ...

  4. 绘图-CAD-改快捷键

    CAD的快捷键应该在左手边,左手不离开键盘,右手不离开鼠标,这样的操作才有效率. arc 圆弧命令原命令是ARC Q 圆(CIRCLE) C 原快捷键C被定义为COPY,Q的形状类似圆,只是多了一个尾 ...

  5. 洛谷 U3346 A1-偶回文数

    U3346 A1-偶回文数 题目背景 方方方很喜欢回文数,于是zzq就出了一道关于回文数的题目. 因为偶回文数比较简单,所以方方方就把它放在了第一题... 题目描述 我们定义一个长度为偶数的回文数叫做 ...

  6. iOS中的crash防护(二)KVC造成的crash

      接上篇< iOS中的crash防护(一)unrecognized selector sent to instance> 我们攻克了找不到方法实现的crash,这一篇我这里主要分析一下在 ...

  7. Codeforces Round #257(Div. 2) B. Jzzhu and Sequences(矩阵高速幂)

    题目链接:http://codeforces.com/problemset/problem/450/B B. Jzzhu and Sequences time limit per test 1 sec ...

  8. Linux下将PHP添加到环境变量,将Mysql加入环境变量。

    1.修改/etc/profile vi /etc/profile 2.添加两行 PATH=$PATH:/usr/local/php7/bin:/usr/local/mysql/bin export P ...

  9. org/eclipse/jetty/util/component/Container$Listener

    转自:https://blog.csdn.net/husheng8891/article/details/10200965?locationNum=9&fps=1 项目Demo开发的时候,发布 ...

  10. Linux就该这么学 20181009(第十二章 SAMBA)

    参考链接https://www.linuxprobe.com Samba 跨平台的文件共享 linux-linux linux-windows /etc/samba/smb.conf 里面 []这个名 ...