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

传送门:>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] 永无乡 「平衡树启发式合并」的更多相关文章

  1. Bzoj 2733: [HNOI2012]永无乡 数组Splay+启发式合并

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3955  Solved: 2112[Submit][Statu ...

  2. Bzoj 2733: [HNOI2012]永无乡(线段树+启发式合并)

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MB Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己 ...

  3. bzoj2733: [HNOI2012]永无乡(splay+启发式合并/线段树合并)

    这题之前写过线段树合并,今天复习Splay的时候想起这题,打算写一次Splay+启发式合并. 好爽!!! 写了长长的代码(其实也不长),只凭着下午的一点记忆(没背板子...),调了好久好久,过了样例, ...

  4. [BZOJ2733][HNOI2010]永无乡 解题报告 启发式合并,线段树合并

    好久没更新博客了,前段时间一直都在考试,都没时间些,现在终于有点闲了(cai guai)... 写了一道题,[HNOI2012]永无乡,其实是一道板子题,我发现我写了好多板子题...还是太菜了... ...

  5. BZOJ2733 永无乡 【splay启发式合并】

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MB Submit: 4190  Solved: 2226 [Submit][Sta ...

  6. P3224 [HNOI2012]永无乡(平衡树合并)

    题目描述 永无乡包含 nn 座岛,编号从 11 到 nn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nn 座岛排名,名次用 11 到 nn 来表示.某些岛之间由巨大的桥连接,通过桥可以从 ...

  7. BZOJ2733 永无乡【splay启发式合并】

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

  8. 2733. [HNOI2012]永无乡【平衡树-splay】

    Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...

  9. BZOJ2733 [HNOI2012]永无乡 【线段树合并】

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...

随机推荐

  1. 关于ArcMap中打开ArcToolbox导致闪退的解决办法

    最近好久不用ArcGis的小编要用到ArcMap去发送一个GP服务,发现按照套路打开ArcMap点击ArcToolbox时,发生了ArcMap的闪退现象,几经周折终于解决了问题. 希望也遇到这类问题的 ...

  2. matlab练习程序(对应点集配准的四元数法)

    这个算是ICP算法中的一个关键步骤,单独拿出来看一下. 算法流程如下: 1.首先得到同名点集P和X. 2.计算P和X的均值up和ux. 3.由P和X构造协方差矩阵sigma. 4.由协方差矩阵sigm ...

  3. javascript Json和String互转

      var jsonText = "{\"id\":\"123\",\"name\":\"tom\",\&qu ...

  4. Java 集合系列(二)—— ArrayList

    ArrayList ArrayList 是通过一个数组来实现的,因此它是在连续的存储位置存放对象的引用,只不过它比 Array 更智能,能够根据集合长度进行自动扩容. 假设让我们来实现一个简单的能够自 ...

  5. Django 【orm】或

    方式一: q=Q() q.connection="or" q.children.append(("pk",1)) q.children.append((&quo ...

  6. Koa 中 ejs 模板的使用

    ejs的基本使用 安装 koa-views 和 ejs npm install --save koa-views/cnpm install --save koa-views npm install e ...

  7. Spring Security(三十六):12. Spring MVC Test Integration

    Spring Security provides comprehensive integration with Spring MVC Test Spring Security提供与Spring MVC ...

  8. Mac进行 usr/bin 目录下修改权限问题,operation not permitted

    一般情况下我们在使用mac系统过程中下载一些文件.新建一些项目之后,这些文件都会默认是只读状态,这时我们只需要简单的一句权限设置命令就可以解决 你要修改文件上层目录的路径 但是我们在对 usr/bin ...

  9. python错误和调试

    在程序运行过程中,总会遇到各种各样的错误. 有的错误是程序编写有问题造成的,比如本来应该输出整数结果输出了字符串,这种错误我们通常称之为bug,bug是必须修复的. 有的错误是用户输入造成的,比如让用 ...

  10. Java面试准备之IO

    Java IO Java IO 分类 Java BIO: 同步并阻塞,服务器实现模式为一个连接一个线程,即客户端有连接请求时服务器端就需要启动一个线程进行处理,如果这个连接不做任何事情会造成不必要的线 ...