题解【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 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...
随机推荐
- JVM新生代老年代详解
1.为什么会有年轻代 我们先来屡屡,为什么需要把堆分代?不分代不能完成他所做的事情么?其实不分代完全可以,分代的唯一理由就是优化GC性能.你先想想,如果没有分代,那我们所有的对象都在一块,GC的时候我 ...
- Scrum立会报告+燃尽图(十二月十日总第四十一次):用户推广
此作业要求参见:https://edu.cnblogs.com/campus/nenu/2018fall/homework/2484 项目地址:https://git.coding.net/zhang ...
- JAVA开发环境的熟悉
北京电子科技学院(BESTI) 实 验 报 告 课程:Java程序设计 班级:1352 姓名:马悦 学号:20135235 成绩: 指导教师:娄嘉鹏 实验日期:2015.4.13 实验密级: 预习程度 ...
- 场景调研 persona
1.姓名:王涛 2.年龄:22 3.收入:基本无收入 4.代表用户在市场上的比例和重要性:王涛为铁道学生.本软件的用户主要是学生和老师,尤其是广大的铁大学子,所以此典型用户的重要性不言而喻,而且比例相 ...
- 软工实践-Beta 冲刺 (7/7)
队名:起床一起肝活队 组长博客:博客链接 作业博客:班级博客本次作业的链接 组员情况 组员1(队长):白晨曦 过去两天完成了哪些任务 描述: 1.界面的修改与完善 展示GitHub当日代码/文档签入记 ...
- React鼠标事件
说明:假设有一个用户名片,当鼠标滑到上面,显示用户详细信息,且用户详情卡片位置随鼠标位置改变而改变. UI框架:Material-ui 实现思路: 1.一个用户简介组件A(用于展示用户列表): 2.一 ...
- Linux下CPU信息的查看
逻辑CPU个数: cat /proc/cpuinfo | grep "processor" | wc -l //32 物理CPU个数: cat /proc/cpuinfo ...
- [转帖漫画]什么是 MD5 算法?---摘要算法 具体算法 一直搞不清楚
漫画:什么是 MD5 算法? 2017-10-05 20:16 来源:伯乐专栏作者/玻璃猫,微信公众号 - 梦见 好文投稿, 请点击 → 这里了解详情 梦见 摘要哈希生成的正确姿势是什么样呢?分三步: ...
- 13个实用的Linux find命令示例
除了在一个目录结构下查找文件这种基本的操作,你还可以用find命令实现一些实用的操作,使你的命令行之旅更加简易. 本文将介绍15种无论是于新手还是老鸟都非常有用的Linux find命令. 首先,在你 ...
- d指针在Qt上的应用及实现(有图,很清楚)
Qt为了使其动态库最大程度上实现二进制兼容,引入了d指针的概念.那么为什么d指针能实现二进制兼容呢?为了回答这个问题,首先弄清楚什么是二进制兼容?所谓二进制兼容动态库,指的是一个在老版本库下运行的程序 ...