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 ...
随机推荐
- 51nod-完美字符串(贪心)
约翰认为字符串的完美度等于它里面所有字母的完美度之和.每个字母的完美度可以由你来分配,不同字母的完美度不同,分别对应一个1-26之间的整数. 约翰不在乎字母大小写.(也就是说字母F和f)的完美度相同. ...
- MVC基于Struts2的CRUD,java+bean+struts
1,所需jar包,将jar包导入lib中 2,项目目录结构 3,struts.xml <?xml version="1.0" encoding="UTF-8&quo ...
- rabbitMQ学习笔记(五) 消息路由
生产者会生产出很多消息 , 但是不同的消费者可能会有不同的需求,只需要接收指定的消息,其他的消息需要被过滤掉. 这时候就可以对消息进行过滤了. 在消费者端设置好需要接收的消息类型. 如果不使用默认的E ...
- Codeforces Round #136 (Div. 1) B. Little Elephant and Array
B. Little Elephant and Array time limit per test 4 seconds memory limit per test 256 megabytes input ...
- 多校第二场 1004 hdu 5303 Delicious Apples(背包+贪心)
题目链接: 点击打开链接 题目大意: 在一个周长为L的环上.给出n棵苹果树.苹果树的位置是xi,苹果树是ai,苹果商店在0位置,人的篮子最大容量为k,问最少做多远的距离可以把苹果都运到店里 题目分析: ...
- 4种方法让SpringMVC接收多个对象
问题背景: 我要在一个表单里同一时候一次性提交多名乘客的个人信息到SpringMVC,前端HTML和SpringMVC Controller里该怎样处理? 第1种方法:表单提交,以字段数组接收: 第2 ...
- java 用JNA调用dll 参考文档
1 Java调用C语言动态库(JNA方式):回调函数.结构体数组传参.结构体数组返回 2jna结构体数组 JNA结构体数组 3JNA调用C语言动态链接库学习实践总结 4 Java 通过 JNA 调 ...
- DPI深度报文检测架构及关键技术实现
DPI深度报文检测架构及关键技术实现 当前DPI(Deep Packet Inspect深度报文识别)技术是安全领域的关键技术点之一,围绕DPI技术衍生出的安全产品类型也非常的多样.在分析DPI的进一 ...
- tp中使用事务
是什么 事务是为了防止,多个操作,其中有失败,数据有部分被执行成功的时候使用的. 比如,银行,用户转账.张三钱扣了,结果李四钱还增加! 这个时候需要使用事务,确保张三钱扣了,李四的钱也增加,才真正的成 ...
- oracle 实时查询最耗CPU资源的SQL语句
1. 先通过top命令查看产用资源较多的spid号 2.查询当前耗时的会话ID,用户名,sqlID等: select sid,serial#,machine,username,program,sql_ ...