☆ [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/ ...
随机推荐
- 微信小程序(二)登录授权实现
相对于上一节,这一节主要是动态获取数据,主要是对登陆信息的接收,以及页面获取授权按钮的相对相应(未授权时,显示,授权后不显示) 关键在于状态值的判断,以及对页面的不同响应(m-->v) wxml ...
- Android八门神器(一): OkHttp框架源码解析
HTTP是我们交换数据和媒体流的现代应用网络,有效利用HTTP可以使我们节省带宽和更快地加载数据,Square公司开源的OkHttp网络请求是有效率的HTTP客户端.之前的知识面仅限于框架API的调用 ...
- mean项目的分模块开发
全文字版: 新建maven工程在,作为父工程用于最后集合使用,该工程不需要src,只需要一个pom.xml文件,规定一下依赖版本之类的,再建一个工具类的工程,不需要放配置文件,和工程中方法接口有关的不 ...
- Windows Java包环境变量的设置
复制Bin文件所在路径 验证
- Xshell连接linux主机
一.获取linux主机的ip地址.用户名.密码 二.xshell里面建立连接 三.打开连接,操作远程linux主机
- 我的第一个python web开发框架(35)——权限数据库结构设计
接下来要做的是权限系统的数据库结构设计,在上一章我们了解了权限系统是通过什么来管理好权限的,我们选用其中比较常用的权限系统来实现当前项目管理要求. 下面是我们选择的权限系统关系模型: 从以上关系可以看 ...
- WPF中窗体最大化问题处理
遇到的问题信息 问题:当WindowStyle=None时,窗口最大化,不显示任务栏 -- 即窗体是全屏效果. 解决中遇到的问题列表[主要涉及到任务栏发生改变后的一些问题处理]: 最大化时,任务栏被遮 ...
- RabbitMQ广播:direct模式
一. 消息的广播需要exchange:exchange是一个转发器,其实把消息发给RabbitMQ里的exchange fanout: 所有bind到此exchange的queue都可以接收消息,广播 ...
- 【转】简单理解Vue中的nextTick
前言: Vue中的nextTick涉及到Vue中DOM的异步更新,感觉很有意思,特意了解了一下.其中关于nextTick的源码涉及到不少知识,很多不太理解,暂且根据自己的一些感悟介绍下nextTick ...
- websocket 实现单聊群聊 以及 握手原理+加密方式
WebSocket 开始代码 服务端 群聊 # type:WebSocket 给变量标注类型 # websocket web + socket from geventwebsocket.server ...