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维护子树信息 + 树的重心的更多相关文章

  1. luoguP3979 遥远的国度 LCT+multiset维护子树信息

    Code: #include<bits/stdc++.h> #define maxn 150000 #define ll long long #define inf 21474836470 ...

  2. bzoj3510 首都 LCT 维护子树信息+树的重心

    题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=3510 题解 首先每一个连通块的首都根据定义,显然就是直径. 然后考虑直径的几个性质: 定义:删 ...

  3. BZOJ 3306: 树 LCT + set 维护子树信息

    可以作为 LCT 维护子树信息的模板,写的还是比较优美的. 本地可过,bzoj 时限太紧,一直 TLE #include<bits/stdc++.h> #define setIO(s) f ...

  4. BZOJ.3510.首都(LCT 启发式合并 树的重心)

    题目链接 BZOJ 洛谷 详见这. 求所有点到某个点距离和最短,即求树的重心.考虑如何动态维护. 两棵子树合并后的重心一定在两棵树的重心之间那条链上,所以在合并的时候用启发式合并,每合并一个点检查sz ...

  5. BZOJ 3510 首都 (LCT)

    洛谷P4299传送门 题目大意:给你一颗树,边是一条一条连上去的 在连接过程中会存在询问,询问当前节点所在联通块(其实是一颗树)的重心是哪个节点 以及森林中所有树的重心的异或和 在做这道题之前,要先了 ...

  6. bzoj 2809 可并堆维护子树信息

    对于每个节点,要在其子树中选尽量多的节点,并且节点的权值和小于一个定值. 建立大根堆,每个节点从儿子节点合并,并弹出最大值直到和满足要求. /***************************** ...

  7. 【bzoj3510】首都 LCT维护子树信息(+启发式合并)

    题目描述 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打败了B国,那么B国将永远从这个星球消失, ...

  8. 【BZOJ3510】首都 LCT维护子树信息+启发式合并

    [BZOJ3510]首都 Description 在X星球上有N个国家,每个国家占据着X星球的一座城市.由于国家之间是敌对关系,所以不同国家的两个城市是不会有公路相连的. X星球上战乱频发,如果A国打 ...

  9. BZOJ 3639: Query on a tree VII LCT_set维护子树信息

    用 set 维护子树信息,细节较多. Code: #include <cstring> #include <cstdio> #include <algorithm> ...

随机推荐

  1. solaris11-text-安装GUI(gnome)

      http://blog.chinaunix.net/xmlrpc.php?r=blog/article&uid=45057&id=3018467 1.下载所需的资源Text Ins ...

  2. 软件测试之怎么避免Bug漏测?

    一.对需求评审阶段,对业务需求细节理解不明确,未深入挖掘隐含拓展需求 改进措施 需求评审前,我们应该先仔细阅读prd及交互文档,先形成自己对产品的思考,通过脑图的方式列出对产品设计的疑问点,从用户或者 ...

  3. oracle级联操作

    在加入foreing key约束时,还能够指定级联操作的类型,主要用于确定当删除(on delete) 附表中的一条记录时,怎样处理子表中的外键字段,有例如以下三种引用类型. cascade 此key ...

  4. Android之QQ授权登录获取用户信息

    有时候我们开发的app须要方便用户简单登录.能够让用户使用自己的qq.微信.微博登录到我们自己开发的app. 今天就在这里总结一下怎样在自己的app中集成QQ授权登录获取用户信息的功能. 首先我们打开 ...

  5. Yum重装走过的坑

    今天因为用yum方式安装mongo遇到报错,从而我选择卸载yum并重新安装. 我先选择了用rpm方式进行重装,从163的packages列表里面找到64位redhat6.5可以用的三个rpm包,安装过 ...

  6. HibernateBaseDAO

    HibernateBaseDAO接口 package com.iotek.homework.dao; import java.io.Serializable; import java.util.Lis ...

  7. Android 6.0 中TimePicker显示为滚动样式的方法

    在Android6.0中,TimePicker控件的默认样式为转盘的样式,就像这个样子: 如果想要显示为之前的滚动样式的话也很简单,只要在布局文件中设置TimePicker的timePickerMod ...

  8. 第14课 SourceTree程序操作介绍

    http://www.atlassian.com/software/sourcetree/overview https://www.microsoft.com/net/framework/versio ...

  9. c++调用DOS命令,不显示黑屏

    WinExec("Cmd.exe /C md c://12", SW_HIDE); 注释:/c是什么意思,不用/C会报错 CMD [/A | /U] [/Q] [/D] [/E:O ...

  10. Newtonsoft.Json 序列化日期问题解决

    上代码 其中的使用方法和UserInfo实体对象就不贴代码了. /// <summary> /// 把对象转成json字符串 /// </summary> /// <pa ...