☆ [HNOI2012] 永无乡 「平衡树启发式合并」
题目类型:平衡树启发式合并
传送门:>Here<
题意:节点可以连边(不能断边),询问任意两个节点的连通性与一个连通块中排名第\(k\)的节点
解题思路
如果不需要询问排名,那么并查集即可。如果只询问排名第一,那么左偏树即可。现在要询问排名第\(k\)小,就需要用平衡树来解决
平衡树求解排名第\(k\)是轻而易举的,然而怎么合并两棵平衡树呢?
启发式合并。所谓启发式合并,就是暴力合并……
所谓启发式合并(不仅仅是平衡树),就是比较要合并的两个结构,选择较小的那一个结构,将其中节点一个一个拆下来插入到较大的那个结构中去。因此当我们合并两棵平衡树时,将\(size\)较小的那一颗平衡树中的节点一个一个拆下来插入到较大的那棵平衡树上。
按什么顺序拆呢?如果每次选择根节点删除然后插入显得很愚蠢。我们尽可能优化删除的情况(插入不可能优化了吧……)——按照后序遍历的顺序来插入。这样的话当我插入一个节点时,它的左右子树肯定都已经没了,因此只需要简单地将自己删除就好了。
Code
/*By DennyQi 2018*/
#include <cstdio>
#include <queue>
#include <cstring>
#include <algorithm>
#define r read()
using namespace std;
typedef long long ll;
const int MAXN = 100010;
const int INF = 1061109567;
inline int Max(const int a, const int b){ return (a > b) ? a : b; }
inline int Min(const int a, const int b){ return (a < b) ? a : b; }
inline int read(){
int x = 0; int w = 1; register char c = getchar();
for(; c ^ '-' && (c < '0' || c > '9'); c = getchar());
if(c == '-') w = -1, c = getchar();
for(; c >= '0' && c <= '9'; c = getchar()) x = (x<<3) + (x<<1) + c - '0'; return x * w;
}
int N,M,q,A,B,x,y; char opt[10];
int val[MAXN],bel[MAXN],rt[MAXN];
struct Splay{
int ch[MAXN][2],fa[MAXN],size[MAXN];
inline bool rson(int f, int x){
return ch[f][1] == x;
}
inline void update(int x){
size[x] = size[ch[x][0]] + size[ch[x][1]] + 1;
}
inline void rotate(int x){
int f = fa[x], gf = fa[f];
int p = rson(f, x), q = !p;
if(!gf) rt[bel[x]] = x; else ch[gf][rson(gf,f)] = x;
fa[x] = gf;
ch[f][p] = ch[x][q], fa[ch[x][q]] = f;
ch[x][q] = f, fa[f] = x;
update(f), update(x);
}
inline void splay(int x, int target){
int f,gf;
while(fa[x] != target){
f = fa[x], gf = fa[f];
if(gf == target){
rotate(x); break;
}
if(rson(gf,f) ^ rson(f,x)) rotate(x); else rotate(f);
rotate(x);
}
}
inline void insert(int A, int x){
int o = rt[A];
while(o){
bool b = val[x] > val[o];
if(!ch[o][b]){
ch[o][b] = x;
fa[x] = o;
bel[x] = A;
size[x] = 1;
splay(x, 0);
break;
}
o = ch[o][b];
}
}
void HEmerge(int A, int x){
if(ch[x][0]) HEmerge(A, ch[x][0]);
if(ch[x][1]) HEmerge(A, ch[x][1]);
insert(A, x);
}
inline void merge(int A, int B){
if(size[rt[A]] < size[rt[B]]) swap(A, B);
HEmerge(A, rt[B]);
rt[B] = 0;
}
inline int query(int A, int k){
int o = rt[A];
if(size[o] < k) return -1;
while(o){
if(size[ch[o][0]] >= k){
o = ch[o][0];
}
else if(size[ch[o][0]] + 1 < k){
k -= size[ch[o][0]] + 1;
o = ch[o][1];
}
else{
return o;
}
}
}
}qxz;
int main(){
N = r, M = r;
for(int i = 1; i <= N; ++i){
val[i] = r;
rt[i] = i;
bel[i] = i;
qxz.size[i] = 1;
}
for(int i = 1; i <= M; ++i){
A = r, B = r;
if(bel[A] != bel[B]) qxz.merge(bel[A], bel[B]);
}
scanf("%d", &q);
while(q--){
scanf("%s %d %d", opt, &x, &y);
if(opt[0] == 'B'){
if(bel[x] == bel[y]) continue;
qxz.merge(bel[x], bel[y]);
}
else{
printf("%d\n", qxz.query(bel[x], y));
}
}
return 0;
}
☆ [HNOI2012] 永无乡 「平衡树启发式合并」的更多相关文章
- Bzoj 2733: [HNOI2012]永无乡 数组Splay+启发式合并
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3955 Solved: 2112[Submit][Statu ...
- Bzoj 2733: [HNOI2012]永无乡(线段树+启发式合并)
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MB Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己 ...
- bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)
这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例, ...
- [BZOJ2733][HNOI2010]永无乡 解题报告 启发式合并,线段树合并
好久没更新博客了,前段时间一直都在考试,都没时间些,现在终于有点闲了(cai guai)... 写了一道题,[HNOI2012]永无乡,其实是一道板子题,我发现我写了好多板子题...还是太菜了... ...
- BZOJ2733 永无乡 【splay启发式合并】
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MB Submit: 4190 Solved: 2226 [Submit][Sta ...
- P3224 [HNOI2012]永无乡(平衡树合并)
题目描述 永无乡包含 nn 座岛,编号从 11 到 nn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nn 座岛排名,名次用 11 到 nn 来表示.某些岛之间由巨大的桥连接,通过桥可以从 ...
- BZOJ2733 永无乡【splay启发式合并】
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
- 2733. [HNOI2012]永无乡【平衡树-splay】
Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...
- BZOJ2733 [HNOI2012]永无乡 【线段树合并】
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
随机推荐
- 【阿里云】在 Windows Server 2016 下使用 FileZilla Server 安装搭建 FTP 服务
Windows Server 2016 下使用 FileZilla Server 安装搭建 FTP 服务 一.安装 Filezilla Server 下载最新版本的 Filezilla Server ...
- 操作系统:修改VirtualBox for Mac的虚拟硬盘大小
我安装的是Mac版的VirtualBox,不能从GUI上修改硬盘大小,但是实在是大小不够用了. 百度后得知,可以用命令行修改. 1.打开终端,输入sudo su,取得管理员权限 $ sudo su P ...
- [Web][高中同学毕业分布去向网站+服务器上挂载]二、敲定思路与方向(HTML5+JS(JQuery+ECharts))
高中同学毕业分布网站:敲定思路 一.背景 第一集:http://www.cnblogs.com/Twobox/p/8368121.html 中大体确定了自己的 大体目标.大体思路. 但是 . 在今天的 ...
- 单台MongoDB实例开启Oplog
背景 随着数据的积累,MongoDB中的数据量越来越大,数据分析团队从数据库中抽取变化数据(假如依据栏位createdatetime,transdatetime),越来越困难.我们知道MongoDB的 ...
- python之生成随机密码
https://www.cnblogs.com/evablogs/p/7096583.html 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #!/usr/bin/py ...
- Django 数据流程图
根据学习Django并且通过几个作业,发现Django制作网站的数据流程有些比较难懂,所以制作一个数据流程图,帮助自己理解,也希望对正学习的人有所帮助! 别的不多说,上美图:
- 20181218-PostgreSQL数据库Extension管理
20181218-PostgreSQL数据库Extension管理 注意:在集群的一个数据库中安装扩展,在集群的另一个数据库要使用的话,仍需安装 1. 查看当前已安装Extension postgre ...
- java反射(java.lang.reflect) ---普通单例模式唯一性问题
1. 普通的饱汉式.饿汉式 package org.bighead.test2; public class TestPrivate { private String str = "strPr ...
- Python Docker 查看私有仓库镜像【转】
文章来源:python Docker 查看私有仓库镜像 pip 安装: # 首先安装epel扩展源: yum -y install epel-release # 更新完成之后,就可安装pip: yum ...
- 8-过滤器Filter和监听器Listener
一.web监听器:监听特殊事件的发生1.监听实现步骤 a.写一个java类,实现特定的接口,重写相关方法 b.在web.xml中,牌配置 <listener> <listener-c ...