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> ...
随机推荐
- POJ 1376 Robot
Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 7866 Accepted: 2586 Description The R ...
- [bzoj2989]数列_KD-Tree_旋转坐标系
数列 bzoj-2989 题目大意:题目链接. 注释:略. 想法:显然,我们用x和a[x]两个值建立笛卡尔坐标系. 两个点之间的距离为曼哈顿距离. 修改操作就是插入... 查询操作就是查询一个点周围的 ...
- .NET几大热点问题(.NET人员必读)
下面收集了关于.NET几大热点问题及简要答案,防止我们回答问题不专业的尴尬.同一时候还将一些.NET资源的相关网址罗列一二. 一.什么是.Net?它主要包含什么? .Net是为简化在第三代因特网的高 ...
- MongoDB改动、删除文档的域属性实例
MongoDB改动.删除文档的域属性实例 在站点的开发中,可能最初的设计不合理.或者后期业务的变更,会造成文档结构会有些无用的属性.须要去删除或改动.因为MongoDB 是无 Schema 的,不像关 ...
- 泛型和面向对象C++
1. 在类内部定义的函数默觉得inline,内联函数应该在头文件里定义,由于其定义对编译器必须是可见的,以便编译器可以在调用点内联展开该函数的代码. 此时,仅有函数原型是不够的. 2.assert 3 ...
- 【Android】开发优化之——调优工具:TrackView,Method Profiling
Android SDK自带的tool TrackView 位于 sdk的tools文件夹下.使用方法为:进入到tools下,执行 traceview e:\loginActivityTracing.t ...
- The Elder HDU - 5956
/* 树上斜率优化 一开始想的是构造出一个序列 转化成一般的dp但是可能被卡 扫把状的树的话可能变成n*n 其实可以直接在树上维护这个单调队列 dfs虽然搞得是一棵树,但是每次都是dfs到的都是一个序 ...
- 将TensorFlow模型变为pb——官方本身提供API,直接调用即可
TensorFlow: How to freeze a model and serve it with a python API 参考:https://blog.metaflow.fr/tensorf ...
- string 类型的翻转
#include <string>#include <iostream>#include <stack> int main() { std::string str= ...
- 99.ext afteredit事件详解
转自:http://www.jcodecraeer.com/a/jquery_js_ajaxjishu/2012/0524/203.html 1 摘要 grid.on(afteredit,afterE ...