BZOJ 3510: 首都 LCT + multiset维护子树信息 + 树的重心
Description
在X星球上有N个国家,每个国家占据着X星球的一座城市。由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的。
X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失,而B国的国土也将归A国管辖。A国国王为了加强统治,会在A国和B国之间修建一条公路,即选择原A国的某个城市和B国某个城市,修建一条连接这两座城市的公路。
同样为了便于统治自己的国家,国家的首都会选在某个使得其他城市到它距离之和最小的城市,这里的距离是指需要经过公路的条数,如果有多个这样的城市,编号最小的将成为首都。
现在告诉你发生在X星球的战事,需要你处理一些关于国家首都的信息,具体地,有如下3种信息需要处理:
1、A x y:表示某两个国家发生战乱,战胜国选择了x城市和y城市,在它们之间修建公路(保证其中城市一个在战胜国另一个在战败国)。
2、Q x:询问当前编号为x的城市所在国家的首都。
3、Xor:询问当前所有国家首都编号的异或和。
Input
第一行是整数N,M,表示城市数和需要处理的信息数。
接下来每行是一个信息,格式如题目描述(A、Q、Xor中的某一种)。
Output
输出包含若干行,为处理Q和Xor信息的结果。
有一个性质,连接两个树,新树的重心一定在原来两个树重心的连线上.
每次连接时,只需在两个重心相连的链上特判一下即可.
具体怎么判呢 ?我们先把这个链给 $split$ 出来.
我们知道,树的重心的最大儿子的大小不会超过总大小的一半,只要找到那个最大儿子大小不超过总大小一半的点即可.
具体的,我们在 $splay$ 上二分,查询一下当前点的最大儿子的大小.
如果左面的总大小更大,就走到左面,否则,走到右面.
每碰到一个可以作为重心的就更新一下答案即可.
#include<bits/stdc++.h>
#define maxn 200000
#define inf 1000000000
using namespace std;
void setIO(string s)
{
string in=s+".in",out=s+".out";
freopen(in.c_str(),"r",stdin);
}
multiset<int>sonmax[maxn];
int n,Q,X=0;
int siz[maxn],son[maxn],p[maxn];
char str[20];
void init() { for(int i=0;i<maxn;++i) p[i]=i; }
int find(int x)
{
return p[x]==x?x:p[x]=find(p[x]);
}
namespace tr
{
#define isrt(x) (!(ch[f[x]][0]==x||ch[f[x]][1]==x))
#define get(x) (ch[f[x]][1]==x)
#define lson ch[x][0]
#define rson ch[x][1]
int ch[maxn][2],f[maxn],rev[maxn],sta[maxn];
void mark(int x)
{
if(!x)return;
swap(lson,rson), rev[x]^=1;
}
void pushup(int x)
{
if(!x)return;
siz[x]=siz[lson]+siz[rson]+son[x]+1;
}
void rotate(int x)
{
int old=f[x],fold=f[old],which=get(x);
if(!isrt(old)) ch[fold][ch[fold][1]==old]=x;
ch[old][which]=ch[x][which^1],f[ch[old][which]]=old;
ch[x][which^1]=old,f[old]=x,f[x]=fold;
pushup(old),pushup(x);
}
void pushdown(int x)
{
if(!rev[x]||!x)return;
mark(lson), mark(rson),rev[x]^=1;
}
void splay(int x)
{
int v=0,u=x,fa;
sta[++v]=u;
while(!isrt(u)) sta[++v]=f[u],u=f[u];
while(v) pushdown(sta[v--]);
for(u=f[u];(fa=f[x])!=u;rotate(x))
if(f[fa]!=u)
rotate(get(x)==get(fa)?fa:x);
}
void Access(int x)
{
int t=0;
while(x)
{
splay(x);
son[x]=son[x]+siz[rson]-siz[t];
if(t) sonmax[x].erase(sonmax[x].lower_bound(-siz[t]));
if(rson) sonmax[x].insert(-siz[rson]);
rson=t;
pushup(x);
t=x,x=f[x];
}
}
void MakeRoot(int x)
{
Access(x), splay(x), mark(x);
}
void split(int x,int y)
{
MakeRoot(x),Access(y),splay(y);
}
void link(int x,int y)
{
MakeRoot(x), MakeRoot(y);
f[x]=y, son[y]+=siz[x];
sonmax[y].insert(-siz[x]);
pushup(y);
x=find(x),y=find(y);
split(x,y); // y is on top of x
int size=siz[y]>>1;
int now=y,ls=0,rs=0,newg=n+233;
while(now)
{
pushdown(now);
int lsum=ls+siz[ch[now][0]],rsum=rs+siz[ch[now][1]];
if(lsum<=size&&rsum<=size&&(-*sonmax[now].begin())<=size) newg=min(newg,now);
if(lsum>rsum) rs+=siz[ch[now][1]]+son[now]+1,now=ch[now][0];
else ls+=siz[ch[now][0]]+son[now]+1, now=ch[now][1];
}
splay(newg);
p[x]=p[y]=p[newg]=newg;
X^=x,X^=y,X^=newg;
}
};
int main()
{
// setIO("input");
init();
scanf("%d%d",&n,&Q);
for(int i=1;i<=n;++i) X^=i,sonmax[i].insert(3);
int x,y,a,b,c,d;
while(Q--)
{
scanf("%s",str);
switch(str[0])
{
case 'A' :
{
scanf("%d%d",&x,&y);
tr::link(x,y);
break;
}
case 'Q' :
{
scanf("%d",&x);
printf("%d\n",find(x));
break;
}
case 'X' :
{
printf("%d\n",X);
break;
}
}
}
return 0;
}
BZOJ 3510: 首都 LCT + multiset维护子树信息 + 树的重心的更多相关文章
- luoguP3979 遥远的国度 LCT+multiset维护子树信息
Code: #include<bits/stdc++.h> #define maxn 150000 #define ll long long #define inf 21474836470 ...
- bzoj3510 首都 LCT 维护子树信息+树的重心
题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删 ...
- BZOJ 3306: 树 LCT + set 维护子树信息
可以作为 LCT 维护子树信息的模板,写的还是比较优美的. 本地可过,bzoj 时限太紧,一直 TLE #include<bits/stdc++.h> #define setIO(s) f ...
- BZOJ.3510.首都(LCT 启发式合并 树的重心)
题目链接 BZOJ 洛谷 详见这. 求所有点到某个点距离和最短,即求树的重心.考虑如何动态维护. 两棵子树合并后的重心一定在两棵树的重心之间那条链上,所以在合并的时候用启发式合并,每合并一个点检查sz ...
- BZOJ 3510 首都 (LCT)
洛谷P4299传送门 题目大意:给你一颗树,边是一条一条连上去的 在连接过程中会存在询问,询问当前节点所在联通块(其实是一颗树)的重心是哪个节点 以及森林中所有树的重心的异或和 在做这道题之前,要先了 ...
- bzoj 2809 可并堆维护子树信息
对于每个节点,要在其子树中选尽量多的节点,并且节点的权值和小于一个定值. 建立大根堆,每个节点从儿子节点合并,并弹出最大值直到和满足要求. /***************************** ...
- 【bzoj3510】首都 LCT维护子树信息(+启发式合并)
题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...
- 【BZOJ3510】首都 LCT维护子树信息+启发式合并
[BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打 ...
- BZOJ 3639: Query on a tree VII LCT_set维护子树信息
用 set 维护子树信息,细节较多. Code: #include <cstring> #include <cstdio> #include <algorithm> ...
随机推荐
- 洛谷 P3496 [POI2010]GIL-Guilds
P3496 [POI2010]GIL-Guilds 题目描述 King Byteasar faces a serious matter. Two competing trade organisatio ...
- 固定一个div在浏览器底部
转自原文 如何固定一个div在浏览器底部 方法1:使用CSS绝对定位 div{ position:absolute; bottom:0px; left:0px; } 方法2:使用CSS固定定位 d ...
- http协议的再次理解
1.Tomcat是根据server.xml的配置启动的.根目录下conf/server.xml. 2.Tomcat是根据server.xml的配置启动的.根目录下conf/server.xml. 3. ...
- eclipse中Client/Server程序生成exe
先建两个Java Project项目,一个写Client,一个写Server端程序,程序大致为一个Server端建立监听某个port.多个Client端能够连接,实现例如以下: 1. Ser ...
- Hadop使用Partitioner后,结果还是一个文件,怎样解决??
近期看了一下partitioner.于是照着写了一个列子.最后发现程序并没有将结果分开写入对应的文件,结果还是一个文件,于是乎感觉是不是没实用集群去执行程序,发现control中还是本地执行的代码: ...
- C# winform 组件---- folderBrowserDialog与openFileDialog(转)
C# winform 组件---- folderBrowserDialog与openFileDialog 2009-06-27 13:36 2153人阅读 评论(1) 收藏 举报 winformc#b ...
- class--类①
原来看其他人的代码,发现有好多class之类的语句,当时没太注意.可后来,我觉得应该有学习新知识的必要了. 类定义是以关键字 class 开头,后跟类的名称.类的主体是包含在一对花括号中.类定义后必须 ...
- RecastNavigation(3D场景建模、网格导航)
一.RecastNavigation详解 RecastNavigation定义: RecastNavigation是一个导航寻路工具集,使用邻接的凸多边形集合描述一个3D场景,A*寻路算法使3D场景的 ...
- A - Diverse Team
Problem description There are n students in a school class, the rating of the i-th student on Codeho ...
- RabbitMQ 官方NET教程(五)【Topic】
在上一个教程中,我们改进了我们的日志记录系统.我们使用direct类型转发器,使得接收者有能力进行选择性的接收日志,,而非fanout那样,只能够无脑的转发 虽然使用direct类型改进了我们的系统, ...