BZOJ 3510 首都 (LCT)
题目大意:给你一颗树,边是一条一条连上去的
在连接过程中会存在询问,询问当前节点所在联通块(其实是一颗树)的重心是哪个节点
以及森林中所有树的重心的异或和
在做这道题之前,要先了解树的重心的一个性质:
两棵树合并时,新树的重心在合并后,原来两颗树的重心的两个节点构成的那条链上
了解了这条性质,思路就不难想了
当连接两个节点时,先寻找它们所在原树的重心,然后连接这两个节点,在取出两个原树重心那两个节点构成的那条链
每次寻找重心,连接节点,取出重心形成了链,复杂度约为
如果我们暴力跑这条链,最差的情况是每次合并时,两颗树都是等长的链,然后像线段树那样从下往上合并,合并次数最多是次,注意符合条件的重心最多只有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)的更多相关文章
- BZOJ.3510.首都(LCT 启发式合并 树的重心)
题目链接 BZOJ 洛谷 详见这. 求所有点到某个点距离和最短,即求树的重心.考虑如何动态维护. 两棵子树合并后的重心一定在两棵树的重心之间那条链上,所以在合并的时候用启发式合并,每合并一个点检查sz ...
- BZOJ 3510: 首都 LCT + multiset维护子树信息 + 树的重心
Code: #include<bits/stdc++.h> #define maxn 200000 #define inf 1000000000 using namespace std; ...
- BZOJ 3510 - 首都 「 $LCT$ 动态维护树的重心」
这题 FlashHu 的优化思路值得借鉴 前置引理 树中所有点到某个点的距离和中,到重心的距离和是最小的. 把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上. 一棵树 ...
- 【刷题】BZOJ 3510 首都
Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从 ...
- bzoj3510 首都 LCT 维护子树信息+树的重心
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删 ...
- 【bzoj3510】首都 LCT维护子树信息(+启发式合并)
题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...
- 【BZOJ3510】首都 LCT维护子树信息+启发式合并
[BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打 ...
- BZOJ 2959 长跑 (LCT+并查集)
题面:BZOJ传送门 当成有向边做的发现过不去样例,改成无向边就忘了原来的思路.. 因为成环的点一定都能取到,我们把它们压成一个新点,权值为环上所有点的权值和 这样保证了图是一颗森林 每次询问转化为, ...
- BZOJ 3306: 树 LCT + set 维护子树信息
可以作为 LCT 维护子树信息的模板,写的还是比较优美的. 本地可过,bzoj 时限太紧,一直 TLE #include<bits/stdc++.h> #define setIO(s) f ...
随机推荐
- 记Spring搭建功能完整的个人博客「Oyster」全过程[其二] Idea中Maven+SpringBoot多模块项目开发的设计和各种坑(模块间依赖和打包问题)
大家好嘞,今天闲着没事干开写写博客,记录一下Maven+SpringBoot的多模块设计和遇到的坑. 多模块设计 简单说明一下截止目前的需求: 需要RESTful API:对文章.标签.分类和评论等的 ...
- Python学习笔记(2)操作符和数据类型
2019-02-25 一: (1)常用操作符: ① 算数操作符:=.-.*./.%(求余).**(幂运算).//(地板除法:计算结果取比商小的最大整型) 注意:幂运算操作符比其左侧的一元运算符的优先级 ...
- Python 之 格式化文件
# 结构化文件存储- xml, json- 为了解决不同设备之间的信息交换 ## XML文件(可扩展标记语言) - 标记语言:语言中使用尖括号括起来的文本字符串标记 - 可扩展:用户可以自己定义需要的 ...
- oracle定时器执行一遍就不执行或本就不执行
转:http://blog.csdn.net/qq_23311211/article/details/76283689 以sqlplus/ assysdba进入sql命令模式,使用sql:select ...
- HDU 5172
超内存了,呃...不知道如何优化了. 首先要判断区间的和是否和1~n的和相等. 再个,记录下每个数字前一次出现的位置,求这些位置的最大值,如果小于左端点,则表示有这样的一个序列. 呃~~~第二个条件当 ...
- HDU 2035 不忍直视的水
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; in ...
- POJ - 3257 Cow Roller Coaster (背包)
题目大意:要用N种材料建一条长为L的路,如今给出每种材料的长度w.起始地点x.发费c和耐久度f 问:在预算为B的情况下,建好这条路的最大耐久度是多少 解题思路:背包问题 dp[i][j]表示起始地点为 ...
- 使用GitHub来托管Larval框架
每个新框架都有自己的安装方法laravel 的安装方法有一下几种: (一) 通过下载 Laravel 包安装 (1) 安装Composer (2) 下载最新Larvel框架 https://g ...
- 【HNOI 2004】宠物收养所
[题目链接] https://www.lydsy.com/JudgeOnline/problem.php?id=1208 [算法] 建两棵平衡树维护领养者和宠物的特点值,这两棵平衡树支持 插入删除,查 ...
- ACM/OI 出题用
之前出题,很苦恼出数据和检查程序,因为很多繁琐的工作,还很可能小手一抖出问题. 最近又在出题...想起之前的对拍脚本,感觉不能更方便,于是撸了一套出题用的小工具,也学习了一点点的DOS命令 首先是输入 ...