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> ...
随机推荐
- jenkins 构建被中断 脚本却还在执行
JobA + git clean -df 构建被中断 被 XXX 终止 Finished: ABORTED 再次jenkins调用JobA 后台进程中 出现了两个JobA的脚本同时执行,导致一些莫名其 ...
- [bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp
Bill的挑战 bzoj-1879 Sdoi-2009 题目大意: 注释:$1\le t \le 5$,$1\le m \le 15$,$1\le length \le 50$. 想法: 又是一个看数 ...
- Spring MVC-表单(Form)标签-单选按钮(RadioButton)示例(转载实践)
以下内容翻译自:https://www.tutorialspoint.com/springmvc/springmvc_radiobutton.htm 说明:示例基于Spring MVC 4.1.6. ...
- Mac OSX:最简单的安装ant方法
安装ant最简单的方法就是通过brew.步骤如下:1. 安装brew(如果已经安装可以跳过这步).ruby -e "$(curl -fsSL https://raw.github.com/m ...
- [Windows]_[0基础]_[Release程序的崩溃报告minidump解决方式]
场景: 1. Release的程序崩溃时,崩溃报告能够让开发者查明代码哪里出了问题,用处大大的. 2. 仅仅实用VS的编译器才支持,所以MinGW就无缘了. 3. 使用了未处理异常过滤处理函数. 4. ...
- UNIX环境编程学习——反思认识
学习情况: 有关UNIX系统环境编程的学习时间用来非常长的时间.可是感觉效果还是不是太好,在中间经过了期末考试.用来非常长的时间用来学习专业课.就将该过程的学习放到了一边上,放假以后又回家造成了 ...
- Android Notification状态栏通知
没有添加额外的震动及声音效果,这里直接实现了通知的功能,看效果吧: MainActivity.java package com.example.notification; import android ...
- 通过loosejar清理应用中冗余的jar包
随着应用规模的逐渐增大,依赖的jar包数量也大幅添加.当中不乏多余的,用不到的jar包,占用了大量的宝贵空间.通过loosejar这个工具.便可轻松找到"滥竽充数"的jar包了~ ...
- storm 并行度
1个worker进程运行的是1个topology的子集(注:不会出现1个worker为多个topology服务).1个worker进程会启动1个或多个executor线程来运行1个topology的c ...
- ningbooj--1655--木块拼接(贪心)
[1655] 木块拼接 时间限制: 1000 ms 内存限制: 65535 K 问题描述 好奇的skyv95想要做一个正方形的木块,现在有三种颜色的矩形木块,颜色分别为"A" ...