Descriprition

两种操作

  1. 把两个集合并起来
  2. 求一个集合中的第 \(k\) 大(的编号)

\(n \leq 10^5\)

Solution

平衡树的板子题之一

维护两个点连不连通直接并查集

考虑怎么把两个集合合并

启发式合并!即把 siz 小的那一颗平衡树每一个点暴力地加入到另一个

这样做的复杂度?对于每一个点,每一次合并之后集合大小都至少是原来的两边,所以每一个点都只会被合并 \(\log n\) 次。所以这样做是 \(O(n \log n)\) 的。

实现上的细节问题:

我用了 fhqtreap(大法好!)。启发式合并的过程(借鉴了题解区里另外一个dalao的fhqtreap)可以这么写:

inline void M(node *&r, node *p) { // p 合并到 r 中
if(!p) return ;
M(r, p->ch[0]); M(r, p->ch[1]); // 递归左子树和右子树
p->ch[0] = p->ch[1] = 0; // 把它左右子清空然后插到 r 里
insert(r, p);
}

Code

#include <bits/stdc++.h>

using namespace std;
const int N = 100100;
int n, m, fa[N];
struct node {
int d, id, siz, rnd;
node *ch[2];
inline void upd() {
int ret = 1;
if(ch[0]) ret += ch[0]->siz;
if(ch[1]) ret += ch[1]->siz;
siz = ret;
}
}pool[N], *cur = pool, *root[N];
inline int find(int x) {
return x == fa[x] ? x : fa[x] = find(fa[x]);
}
inline int siz(node *p) {
if(p) return p->siz; return 0;
}
inline node *newnode(int d, int id) {
node *p = cur++; p->rnd = (rand() << 15) + rand();
p->siz = 1, p->d = d; p->id = id;
p->ch[0] = p->ch[1] = 0;
return p;
}
inline node *merge(node *p, node *q) {
if(!p) return q;
if(!q) return p;
if(p->rnd < q->rnd) { p->ch[1] = merge(p->ch[1], q); p->upd(); return p; }
if(p->rnd >= q->rnd) { q->ch[0] = merge(p, q->ch[0]); q->upd(); return q; }
}
inline void split(node *r, int k, node *&p, node *&q) {
if(!r) { p = q = 0; return ; }
if(siz(r->ch[0]) < k) p = r, split(r->ch[1], k - siz(r->ch[0]) - 1, r->ch[1], q);
else q = r, split(r->ch[0], k, p, r->ch[0]); r->upd();
}
inline int rk(node *r, int x) {
if(!r) return 0;
if(r->d >= x) return rk(r->ch[0], x);
else return rk(r->ch[1], x) + siz(r->ch[0]) + 1;
}
inline void insert(node *&r, node *x) {
node *p, *q; int k = rk(r, x->d);
split(r, k, p, q);
r = merge(merge(p, x), q);
}
inline void M(node *&r, node *p) { // p -> r
if(!p) return ;
M(r, p->ch[0]); M(r, p->ch[1]);
p->ch[0] = p->ch[1] = 0; p->upd(); insert(r, p);
}
inline node *Merge(node *p, node *q) {
if(p->siz <= q->siz) swap(p, q); M(p, q); return p;
}
/*
inline void out(node *p) {
if(p->ch[0]) out(p->ch[0]);
printf("%d ", p->d);
if(p->ch[1]) out(p->ch[1]);
}
*/
int main() {
scanf("%d %d", &n, &m);
for(int i = 1; i <= n; i++) fa[i] = i;
for(int i = 1; i <= n; i++) {
int x; scanf("%d", &x);
root[i] = newnode(x, i);
} int q;
for(int i = 1; i <= m; i++) {
int u, v; scanf("%d %d", &u, &v);
int fu = find(u), fv = find(v);
if(fu == fv) continue ;
root[fu] = Merge(root[fu], root[fv]);
fa[fv] = fu;
}
scanf("%d", &q);
for(int i = 1; i <= q; i++) {
char op[5]; int x, y;
scanf("%s %d %d", op, &x, &y);
if(op[0] == 'B') {
int fx = find(x), fy = find(y);
if(fx == fy) continue ;
root[fx] = Merge(root[fx], root[fy]);
fa[fy] = fx;
} else {
int fx = find(x);
node *p, *q, *r;
if(siz(root[fx]) < y) {
printf("-1\n"); continue ;
}
split(root[fx], y - 1, p, q);
split(q, 1, q, r);
printf("%d\n", q->id);
root[fx] = merge(p, merge(q, r));
}
}
return 0;
}

题解【bzoj2733 [HNOI2012]永无乡】的更多相关文章

  1. bzoj2733: [HNOI2012]永无乡 启发式合并

    地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 题目: 2733: [HNOI2012]永无乡 Time Limit: 10 Sec   ...

  2. bzoj2733: [HNOI2012]永无乡(splay)

    2733: [HNOI2012]永无乡 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 3778  Solved: 2020 Description 永 ...

  3. [Bzoj2733][Hnoi2012] 永无乡(BST)(Pb_ds tree)

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

  4. [bzoj2733][HNOI2012]永无乡_权值线段树_线段树合并

    永无乡 bzoj-2733 HNOI-2012 题目大意:题目链接. 注释:略. 想法: 它的查询操作非常友善,就是一个联通块内的$k$小值. 故此我们可以考虑每个联通块建一棵权值线段树. 这样的话每 ...

  5. bzoj2733: [HNOI2012]永无乡 线段树合并

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

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

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

  7. [BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)

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

  8. BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并

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

  9. BZOJ2733: [HNOI2012]永无乡(线段树合并)

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

随机推荐

  1. 【quickhybrid】Android端的项目实现

    前言 前文中就有提到,Hybrid模式的核心就是在原生,而本文就以此项目的Android部分为例介绍Android部分的实现. 提示,由于各种各样的原因,本项目中的Android容器确保核心交互以及部 ...

  2. 2017-2018-1 Java演绎法 第九、十周 作业

    团队成员 [20162315 马军] [20162316 刘诚昊] [20162317 袁逸灏(组长)] [20162319 莫礼钟] [20162320 刘先润] [20162330 刘伟康] 项目 ...

  3. javascript中的call(),apply(),bind()方法的区别

    之前一直迷惑,记不住call(),apply(),bind()的区别.不知道如何使用,一直处于懵懂的状态.直到有一天面试被问到了这三个方法的区别,所以觉得很有必要总结一下. 如果有不全面的地方,后续再 ...

  4. 【CSAPP笔记】6. 汇编语言——控制

    原先刊于自己的域名下面,考虑到博客园之前发过一半,不想烂尾,故在博客园发一版. 到目前为止我们只考虑了直线代码的执行行为,也就是指令一条接着一条执行.C语言中的某些语句,比如条件语句.循环.分支语句, ...

  5. Socket 记录

    心跳检测步骤:1客户端每隔一个时间间隔发生一个探测包给服务器2客户端发包时启动一个超时定时器3服务器端接收到检测包,应该回应一个包4如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器5如果 ...

  6. CefSharp,Winform程序中加载web网页

    源码地址:https://github.com/cefsharp/CefSharp 开源相关:https://github.com/cefsharp/CefSharp/tree/master/CefS ...

  7. Scrum 项目 3.0

    -------------------------------------3.0----------------------------------------------------- 一.项目工作 ...

  8. Window下JDK安装教程

    1.准备 win10系统,其他windows系统安装过程大同小异官网下载jdk1.8下载地址:https://www.oracle.com/technetwork/java/javase/downlo ...

  9. SQLSERVER 使用XP开头的系统默认存储过程

    1. 根据官网上面的内容进行执行命令 EXEC xp_cmdshell 'dir *.exe'; 但是会报错 消息 ,级别 ,状态 ,过程 xp_cmdshell,行 [批起始行 ] SQL Serv ...

  10. Art & Material

    Art(Android runtime)模式伴随Android 4.4发布.相对于Dalvik模式来说,Art模式改善了Android程序的性能. Material Design伴随Android 5 ...