这个题目很有意思

QWQ

根据题目描述,我们可以知道,首都就是所谓的树的重心,那么我们假设每颗树的重心都是\(root\)的话,对于每次询问,我们只需要\(findroot(x)\)就可以。

那么如何处理\(link\)操作呢QWQ

这里是看了题解,我才知道是怎么做的

大致的思想就是:

!启发式合并!

首先,这里需要注意树的中心具有的两个性质:

1。以这个点为根,那么所有的子树(不算整个树自身)的大小都不超过整个树大小的一半。

2.假设两个联通块x和y进行合并,而且\(size(x)>size(y)\),那么新的重心必然在连接原来两棵树重心的路径上。

那么我们对于一次\(link\),首先要知道两棵树的重心的路径是什么样的,我们可以通过\(link+access\),然后中序遍历来求出来

void dfs(int x,int lim)
{
if (top>lim)
{
flag=true;
return;
}
pushdown(x);
if (ch[x][0]) dfs(ch[x][0],lim);
if (flag) return;
sta[++top]=x;
if (flag) return;
if (ch[x][1]) dfs(ch[x][1],lim);
if (flag) return;
} link(x,y);
access(x);
splay(ry);
dfs(ry,ymh);

一定记得\(dfs\)的时候要\(pushdown\)!!!

同时dfs的时候,如果路径上的点已经要比,较小的子树的size要大,就可以直接\(return\),因为继续下去一定没有意义,就不可能会更新答案了。

然后把这条路径统计出来之后,我们只需要从\(root_大\)开始,看看当前的节点的子树大小*2,是不是大于总的\(size\),如果大于,就移动,不然就\(break\)

int r = ry;
for (int i=1;i<=top;i++)
{
splay(sta[i]);
int now = xv[sta[i]]+1+sum[ch[sta[i]][1]];
if (2*now>size || (2*now==size && sta[i]<=r)) r=sta[i];
else break;
}
makeroot(r);
ans^=r;

大致就是这样,然后对于整体的询问,我们维护一个\(ans\)即可,每次合并之前先异或上两个\(root\),然后最后再异或一下最后合并完的\(root\)

上代码

// luogu-judger-enable-o2
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<cmath>
#include<map>
#include<set> using namespace std; inline int read()
{
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)) {if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
} const int maxn = 3e5+1e2; int ch[maxn][3];
int fa[maxn],rev[maxn],st[maxn];
int n,m;
int sta[maxn];
int sum[maxn],xv[maxn];
int ans; int son(int x)
{
if (ch[fa[x]][0]==x) return 0;
else return 1;
} bool notroot(int x)
{
return ch[fa[x]][0]==x || ch[fa[x]][1]==x;
} void update(int x)
{
sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+xv[x]+1;
} void reverse(int x)
{
swap(ch[x][0],ch[x][1]);
rev[x]^=1;
} void pushdown(int x)
{
if (rev[x])
{
if (ch[x][0]) reverse(ch[x][0]);
if (ch[x][1]) reverse(ch[x][1]);
rev[x]=0;
}
} void rotate(int x)
{
int y=fa[x],z=fa[y];
int b=son(x),c=son(y);
if (notroot(y)) ch[z][c]=x;
fa[x]=z;
ch[y][b]=ch[x][!b];
fa[ch[x][!b]]=y;
ch[x][!b]=y;
fa[y]=x;
update(y);
update(x);
} void splay(int x)
{
int y=x,cnt=0;
st[++cnt]=y;
while (notroot(y)) y=fa[y],st[++cnt]=y;
while (cnt) pushdown(st[cnt--]);
while (notroot(x))
{
int y=fa[x],z=fa[y];
int b=son(x),c=son(y);
if (notroot(y))
{
if (b==c) rotate(y);
else rotate(x);
}
rotate(x);
}
update(x);
} void access(int x)
{
for (int y=0;x;y=x,x=fa[x])
{
splay(x);
xv[x]+=sum[ch[x][1]]-sum[y];
ch[x][1]=y;
update(x);
}
} void makeroot(int x)
{
access(x);
splay(x);
reverse(x);
} int findroot(int x)
{
access(x);
splay(x);
while (ch[x][0])
{
pushdown(x);
x=ch[x][0];
}
return x;
} void split(int x,int y)
{
makeroot(x);
access(y);
splay(y);
} void link(int x,int y)
{
split(x,y);
if (findroot(y)!=x)
{
xv[y]+=sum[x];
fa[x]=y;
update(y);
} } int q;
bool flag=false;
int top; void dfs(int x,int lim)
{
if (top>lim)
{
flag=true;
return;
}
pushdown(x);
if (ch[x][0]) dfs(ch[x][0],lim);
if (flag) return;
sta[++top]=x;
if (flag) return;
if (ch[x][1]) dfs(ch[x][1],lim);
if (flag) return;
} int main()
{
n=read();q=read();
for (int i=1;i<=n;i++) sum[i]=1,ans^=i;
for (int i=1;i<=q;i++)
{
char s[10];
scanf("%s",s+1);
if (s[1]=='X')
{
cout<<ans<<"\n";
}
if (s[1]=='Q')
{
int x=read();
cout<<findroot(x)<<"\n";
}
if (s[1]=='A')
{
int x=read(),y=read();
flag=false;
top=0;
int rx=findroot(x);
splay(rx);
int ry=findroot(y);
splay(ry);
ans^=rx^ry; if (sum[rx]>sum[ry] || (sum[rx]==sum[ry] && rx<ry)) swap(x,y),swap(rx,ry);
int ymh = sum[rx];int size = sum[rx]+sum[ry];
link(x,y);
access(x);
splay(ry);
dfs(ry,ymh);
int r = ry;
for (int i=1;i<=top;i++)
{
splay(sta[i]);
int now = xv[sta[i]]+1+sum[ch[sta[i]][1]];
if (2*now>size || (2*now==size && sta[i]<=r)) r=sta[i];
else break;
}
makeroot(r);
ans^=r;
}
}
return 0;
}

洛谷4299首都(LCT维护动态重心+子树信息)的更多相关文章

  1. 洛谷P4299 首都(BZOJ3510)(LCT,树的重心,二分查找)

    Update:原来的洛谷U21715已成坑qwq 已经被某位管理员巨佬放进公共题库啦!又可以多一个AC记录啦! 洛谷题目传送门 其实也可以到这里交啦 思路分析 动态维护树的重心 题目中说到国家的首都会 ...

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

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

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

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

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

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

  5. bzoj 3295 (洛谷3157、3193) [Cqoi2011]动态逆序对——树套树 / CDQ分治

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3295 题目--洛谷3157:https://www.luogu.org/problemnew ...

  6. [洛谷P4299] 首都

    题目传送门 还是维护子树信息. 但是这里多了一个找重心的操作. 这里有一个关于树重心的结论,据说可以用反证法证明.反正我不会证 就是:新的重心一定在原来两个重心之间的那条树链上. 这样我们逐步缩小搜索 ...

  7. 洛谷P4719 【模板】动态dp(ddp LCT)

    题意 题目链接 Sol 动态dp板子题.有些细节还没搞懂,待我研究明白后再补题解... #include<bits/stdc++.h> #define LL long long using ...

  8. 【BZOJ 3669】 [Noi2014]魔法森林 LCT维护动态最小生成树

    这道题看题意是在求一个二维最小瓶颈路,唯一可行方案就是枚举一维在这一维满足的条件下使另一维最小,那么我们就把第一维排序利用A小的边在A大的情况下仍成立来动态加边维护最小生成树. #include &l ...

  9. luogu P4172 [WC2006]水管局长 LCT维护动态MST + 离线

    Code: #include<bits/stdc++.h> #define maxn 1200000 #define N 120000 using namespace std; char ...

随机推荐

  1. 新东方APP技术团队建设

    作者:张建鑫, 曾任IBM高级软件架构师, 滴滴高级技术专家, 现任新东方集团高级技术总监 2019年注定是不平凡的一年,在俞敏洪老师对科技条线的密切关注下, 吴强老师亲自操盘了对产品技术条线的改革, ...

  2. Ubuntu 16.04 NVidia显卡 输入密码后 重复出现登录界面

    问题根源:显卡驱动 解决办法: CTRL+ALT+F1 # 切换到命令行 sudo service lightdm stop  # 关闭桌面显示管理器 sudo apt-get remove --pu ...

  3. 移动端 uni-app 滑动事件 精确判断手指滑动方向

    移动端根据手指滑动操作判断滑动方向 设计思路: 1.根据移动端touchstart和touchend方法获取手指触摸屏幕的开始坐标和结束坐标 2.根据两个坐标计算与水平方向的夹角 3.根据夹角判断当前 ...

  4. uniapp 设置背景图片

    uniapp 由于其特殊机制,导致了背景图片不能引用本地图片.只能通过 转成 base64 来进行设置 附上链接:https://oktools.net/image2base64 图片转成base64 ...

  5. 阿里云服务器安装配置nginx

    服务器: 阿里云 Alibaba Cloud Linux 下载 进入到预计存放nginx的目录,比如:/usr/local/ 下载nginx压缩包,并解压 cd /usr/local wget htt ...

  6. docker入门及常用命令

    Docker简介 Docker 是一个开源的应用容器引擎,基于 Go 语言 并遵从Apache2.0协议开源. Docker 可以让开发者打包他们的应用以及依赖包到一个轻量级.可移植的容器中,然后发布 ...

  7. tar 命令简介

    tar命令可以为linux的文件和目录创建档案.利用tar,可以为某一特定文件创建档案(备份文件),也可以在档案中改变文件,或者向档案中加入新的文件.tar最初被用来在磁带上创建档案,现在,用户可以在 ...

  8. tornado2.2安装教程

    最近要用到vxworks 系统,所以避免不了要安装tornado 软件,进行相关的开发. 自己在安装过程中遇到了点点问题,这里记录下来,免得以后再次安装时遇到同样的问题. 1.   首先提供一个tor ...

  9. 最全Windows版本jemalloc库(5.2.1)及其使用:包含动态库和静态库、x86版本和x64版本、debug版本和release版本

    编写服务器程序时,需要频繁的申请和释放内存,长时间运行会产生大量的内存碎片,这就导致即使当前系统中的闲置内存还足够多,但也无法申请到大的连续可用的内存块,因为此时的物理内存已经千疮百孔像个马蜂窝.此外 ...

  10. Ubuntu中类似QQ截图的截图工具并实现鼠标右键菜单截图

    @ 目录 简介: 安装: 设置快捷键: 实现鼠标右键菜单截图: 简介: 在Windows中用惯了强大易用的QQ截图,会不习惯Ubuntu中的截图工具. 软件名为火焰截图,功能类似QQ截图,可以设置快捷 ...