博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
☆ [HNOI2012] 永无乡 「平衡树启发式合并」
阅读量:4513 次
发布时间:2019-06-08

本文共 3532 字,大约阅读时间需要 11 分钟。

题目类型:平衡树启发式合并

传送门:><

题意:节点可以连边(不能断边),询问任意两个节点的连通性与一个连通块中排名第\(k\)的节点

解题思路

如果不需要询问排名,那么并查集即可。如果只询问排名第一,那么左偏树即可。现在要询问排名第\(k\)小,就需要用平衡树来解决

平衡树求解排名第\(k\)是轻而易举的,然而怎么合并两棵平衡树呢?

启发式合并。所谓启发式合并,就是暴力合并……

所谓启发式合并(不仅仅是平衡树),就是比较要合并的两个结构,选择较小的那一个结构,将其中节点一个一个拆下来插入到较大的那个结构中去。因此当我们合并两棵平衡树时,将\(size\)较小的那一颗平衡树中的节点一个一个拆下来插入到较大的那棵平衡树上。

按什么顺序拆呢?如果每次选择根节点删除然后插入显得很愚蠢。我们尽可能优化删除的情况(插入不可能优化了吧……)——按照后序遍历的顺序来插入。这样的话当我插入一个节点时,它的左右子树肯定都已经没了,因此只需要简单地将自己删除就好了。

Code

/*By DennyQi 2018*/#include 
#include
#include
#include
#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;}

转载于:https://www.cnblogs.com/qixingzhi/p/9656031.html

你可能感兴趣的文章
js div拖动动画运行轨迹效果
查看>>
使用Struts 2框架实现文件下载
查看>>
把工程部署在tomcat的root路径下
查看>>
topcoder SRM 625 DIV2 AddMultiply
查看>>
Leetcode Climbing Stairs
查看>>
腾讯2013实习笔试题
查看>>
Recipe 1.9. Processing a String One Word at a Time
查看>>
Linux 下查看系统是32位 还是64 位的方法
查看>>
MySQL 引擎 和 InnoDB并发控制 简介
查看>>
Dave Python 练习二
查看>>
Integer类之成员变量
查看>>
菜根谭#179
查看>>
如何获取多个字符串中最长的共同子字符串?
查看>>
Android 开发笔记___textvieww__跑马灯效果
查看>>
[ JS 进阶 ] 闭包,作用域链,垃圾回收,内存泄露
查看>>
GitHub注册与Git安装
查看>>
ThinkPHP 更新数据 save方法
查看>>
Bshare自定义分享按钮
查看>>
11Qt样式表
查看>>
轮询/长轮询
查看>>