题解【bzoj2733 [HNOI2012]永无乡】
Descriprition
两种操作
- 把两个集合并起来
 - 求一个集合中的第 \(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]永无乡】的更多相关文章
- bzoj2733: [HNOI2012]永无乡  启发式合并
		
地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2733 题目: 2733: [HNOI2012]永无乡 Time Limit: 10 Sec ...
 - bzoj2733: [HNOI2012]永无乡(splay)
		
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 3778 Solved: 2020 Description 永 ...
 - [Bzoj2733][Hnoi2012] 永无乡(BST)(Pb_ds tree)
		
2733: [HNOI2012]永无乡 Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 4108 Solved: 2195[Submit][Statu ...
 - [bzoj2733][HNOI2012]永无乡_权值线段树_线段树合并
		
永无乡 bzoj-2733 HNOI-2012 题目大意:题目链接. 注释:略. 想法: 它的查询操作非常友善,就是一个联通块内的$k$小值. 故此我们可以考虑每个联通块建一棵权值线段树. 这样的话每 ...
 - bzoj2733: [HNOI2012]永无乡  线段树合并
		
永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛. ...
 - BZOJ2733 [HNOI2012]永无乡  【线段树合并】
		
本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000 作者博客:http://www.cnblogs.com/ljh2000-jump/ ...
 - [BZOJ2733] [HNOI2012] 永无乡 (splay启发式合并)
		
Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...
 - BZOJ2733[HNOI2012]永无乡——线段树合并+并查集+启发式合并
		
题目描述 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达 ...
 - BZOJ2733: [HNOI2012]永无乡(线段树合并)
		
Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...
 
随机推荐
- 【quickhybrid】Android端的项目实现
			
前言 前文中就有提到,Hybrid模式的核心就是在原生,而本文就以此项目的Android部分为例介绍Android部分的实现. 提示,由于各种各样的原因,本项目中的Android容器确保核心交互以及部 ...
 - 2017-2018-1 Java演绎法 第九、十周 作业
			
团队成员 [20162315 马军] [20162316 刘诚昊] [20162317 袁逸灏(组长)] [20162319 莫礼钟] [20162320 刘先润] [20162330 刘伟康] 项目 ...
 - javascript中的call(),apply(),bind()方法的区别
			
之前一直迷惑,记不住call(),apply(),bind()的区别.不知道如何使用,一直处于懵懂的状态.直到有一天面试被问到了这三个方法的区别,所以觉得很有必要总结一下. 如果有不全面的地方,后续再 ...
 - 【CSAPP笔记】6. 汇编语言——控制
			
原先刊于自己的域名下面,考虑到博客园之前发过一半,不想烂尾,故在博客园发一版. 到目前为止我们只考虑了直线代码的执行行为,也就是指令一条接着一条执行.C语言中的某些语句,比如条件语句.循环.分支语句, ...
 - Socket 记录
			
心跳检测步骤:1客户端每隔一个时间间隔发生一个探测包给服务器2客户端发包时启动一个超时定时器3服务器端接收到检测包,应该回应一个包4如果客户机收到服务器的应答包,则说明服务器正常,删除超时定时器5如果 ...
 - CefSharp,Winform程序中加载web网页
			
源码地址:https://github.com/cefsharp/CefSharp 开源相关:https://github.com/cefsharp/CefSharp/tree/master/CefS ...
 - Scrum 项目 3.0
			
-------------------------------------3.0----------------------------------------------------- 一.项目工作 ...
 - Window下JDK安装教程
			
1.准备 win10系统,其他windows系统安装过程大同小异官网下载jdk1.8下载地址:https://www.oracle.com/technetwork/java/javase/downlo ...
 - SQLSERVER 使用XP开头的系统默认存储过程
			
1. 根据官网上面的内容进行执行命令 EXEC xp_cmdshell 'dir *.exe'; 但是会报错 消息 ,级别 ,状态 ,过程 xp_cmdshell,行 [批起始行 ] SQL Serv ...
 - Art & Material
			
Art(Android runtime)模式伴随Android 4.4发布.相对于Dalvik模式来说,Art模式改善了Android程序的性能. Material Design伴随Android 5 ...