【洛谷P3224】永无乡 并查集+Splay启发式合并
题目大意:给定 N 个点的图,点有点权,初始有一些无向边,现在有 Q 个询问,每个询问支持动态增加一条无向边连接两个不连通的点和查询第 X 个点所在的联通块中权值第 K 大的是哪个点。
题解:学会了平衡树的启发式合并。
以每个点建立一棵平衡树,需要加边时则合并两个点对应的平衡树,启发式的思想在于合并的时候将 size 小的平衡树信息合并到 size 大的树上。这样,对于每一个被合并的点来说,其所在的平衡树的大小必定翻倍,而最极端的话,所有的点都在一个平衡树中,size = n,因此,每个点被合并的次数不超过 \(O(logn)\) 次,即:新建的节点数不超过 \(O(nlogn)\) 个。
需要注意的是,对于 Splay 来说,若对于以前的单个平衡树来说,根节点的父节点可以取 0,但是有 N 棵平衡树的话,每棵平衡树根节点的父节点不能相同,因此,将 tot 初始化成 N,对于第 i 个平衡树的根节点,将 i 作为其父节点,并且根节点需要手动初始化,不能 insert。
连通性什么的直接并查集维护就好喽。
代码如下
#include <bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int n,m,q,f[maxn],mp[maxn];
int find(int x){return x==f[x]?x:f[x]=find(f[x]);}
struct node{
#define ls(x) t[x].ch[0]
#define rs(x) t[x].ch[1]
int ch[2],fa,val,size;
}t[maxn<<3];
int tot,root[maxn];
inline void pushup(int o){t[o].size=t[ls(o)].size+t[rs(o)].size+1;}
inline bool get(int o){return o==rs(t[o].fa);}
inline void rotate(int o){
int fa=t[o].fa,gfa=t[fa].fa;
int d1=get(o),d2=get(fa);
t[fa].ch[d1]=t[o].ch[d1^1],t[t[o].ch[d1^1]].fa=fa;
t[fa].fa=o,t[o].ch[d1^1]=fa;
t[gfa].ch[d2]=o,t[o].fa=gfa;
pushup(fa),pushup(o);
}
inline void splay(int o,int goal){
while(t[o].fa!=goal){
int fa=t[o].fa,gfa=t[fa].fa;
if(gfa!=goal)get(o)==get(fa)?rotate(fa):rotate(o);
rotate(o);
}
if(goal<=n)root[goal]=o;
}
void insert(int val,int i){
int o=root[i],fa=0;
while(o)fa=o,o=t[o].ch[t[o].val<val];
o=++tot;
if(fa)t[fa].ch[t[fa].val<val]=o;
t[o].fa=fa,t[o].val=val,t[o].size=1;
splay(o,i);
}
int kth(int o,int k){
if(k<=t[ls(o)].size)return kth(ls(o),k);
else if(k>t[ls(o)].size+1)return kth(rs(o),k-t[ls(o)].size-1);
else return t[o].val;
}
void dfs(int o,int i){
if(ls(o))dfs(ls(o),i);
if(rs(o))dfs(rs(o),i);
insert(t[o].val,i);
}
void merge(int a,int b){
if(!a||!b)return;
int x=find(a),y=find(b);
if(x==y)return;
if(t[root[x]].size>t[root[y]].size)swap(x,y);
f[x]=y;
dfs(root[x],y);
}
void read_and_parse(){
scanf("%d%d",&n,&m),tot=n;
for(int i=1,val;i<=n;i++){
scanf("%d",&val);
f[i]=i,mp[val]=i;
root[i]=++tot,t[root[i]].fa=i,t[root[i]].size=1,t[root[i]].val=val;
}
for(int i=1,a,b;i<=m;i++){
scanf("%d%d",&a,&b);
merge(a,b);
}
}
void solve(){
char opt[2];int x,y;
scanf("%d",&q);
while(q--){
scanf("%s%d%d",opt,&x,&y);
if(opt[0]=='B')merge(x,y);
else{
if(y>t[root[find(x)]].size)puts("-1");
else printf("%d\n",mp[kth(root[find(x)],y)]);
}
}
}
int main(){
read_and_parse();
solve();
return 0;
}
【洛谷P3224】永无乡 并查集+Splay启发式合并的更多相关文章
- 洛谷P3224 永无乡 [HNOI2012] 线段树/splay/treap
正解:线段树合并 解题报告: 传送门! 这题也是有很多解法,eg:splay,treap,... 然而我都不会我会学的QAQ! 反正今天就只讲下线段树合并怎么做QAQ 首先看到这样子的说第k重要的是什 ...
- BZOJ2733 [HNOI2012]永无乡(并查集+线段树合并)
题目大意: 在$n$个带权点上维护两个操作: 1)在点$u,v$间连一条边: 2)询问点$u$所在联通块中权值第$k$小的点的编号,若该联通块中的点的数目小于$k$,则输出$-1$: 传送门 上周的模 ...
- 洛谷 [P3224] 永无乡
Treap 的合并 首先感谢 @Capella 的DeBug 其次,这是由一个 & 号引发的血案 注意对于所有修改操作都要 & Treap的合并, 启发式合并,对于每一个节点都 ins ...
- bzoj 2733 永无乡 - 并查集 - 线段树
永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛. ...
- BZOJ 2733 [HNOI2012]永无乡 (权值线段树启发式合并+并查集)
题意: n<=1e5的图里,在线连边.查询某连通块第k大 思路: 练习线段树合并的好题,因为依然记得上一次启发式合并trie的时候内存爆炸的恐怖,所以这次还是用了动态开点.回收 听说启发式合并s ...
- 【BZOJ2733】永无乡(线段树,启发式合并)
题意:支持合并,求块内K小数 对于 100%的数据 n≤100000,m≤n,q≤300000 思路:对于每一个块建立一棵动态开点的线段树,暴力(启发式?)合并后二分下就行了 merge用函数的方式写 ...
- B20J_2733_[HNOI2012]永无乡_权值线段树合并
B20J_2733_[HNOI2012]永无乡_权值线段树合并 Description:n座岛,编号从1到n,每座岛都有自己的独一无二的重要度,按照重要度可以将这n座岛排名,名次用1到 n来表示.某些 ...
- 洛谷P1525 关押罪犯(并查集、二分图判定)
本人蒟蒻,只能靠题解AC,看到大佬们的解题思路,%%%%%% https://www.luogu.org/problemnew/show/P1525 题目描述 S城现有两座监狱,一共关押着N名罪犯,编 ...
- Bzoj1015/洛谷P1197 [JSOI2008]星球大战(并查集)
题面 Bzoj 洛谷 题解 考虑离线做法,逆序处理,一个一个星球的加入.用并查集维护一下连通性就好了. 具体来说,先将被消灭的星球储存下来,先将没有被消灭的星球用并查集并在一起,这样做可以路径压缩,然 ...
随机推荐
- 身在上海的她,该不该继续"坚持"前端开发?
作者:13 GitHub:https://github.com/ZHENFENG13 版权声明:本文为原创文章,未经允许不得转载. 一 对于目前的IT行业,我实在不想她还没在这个行业中站稳脚跟就开始有 ...
- layui表格和弹出框的简单示例
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="C ...
- Html5计算MD5值
教程: http://www.tuicool.com/articles/InEBNz 组件: https://github.com/satazor/js-spark-md5
- MFS+Keepalived双机高可用热备方案操作记录
基于MFS的单点及手动备份的缺陷,考虑将其与Keepalived相结合以提高可用性.在Centos下MooseFS(MFS)分布式存储共享环境部署记录这篇文档部署环境的基础上,只需要做如下改动: 1) ...
- B. Forgery
链接 [http://codeforces.com/contest/1059/problem/B] 题意 要伪造医生签名,先给你医生的签名nm的网格'.'表示空白',#'表示墨水,你的笔可以这么画以一 ...
- linux及安全第六周总结
进程控制块pcb——task_struct 操作系统三大功能: 进程管理(核心) 内存管理 文件系统 为了管理进程,内核必须对每个进程进行清晰的描述,进程描述符提供了内核所需了解的进程信息: 进程状态 ...
- 用软件工程分析开源项目octave的移植
在本科的时候学习了软件工程,报考了信息系统项目管理师的考试,,虽然没有过,但是其实还是学了一些相关项目管理方面的知识,,9大管理,,当年应该能背出来,,, 1 项目整体管理 2 项目范围管理 3 项目 ...
- 四则运算安卓版ver.mk3
在原有的基础上做了些许改动以及添加了一点小功能,以下是代码: package com.example.add; import java.io.File; import com.example.add. ...
- Xcode自动选择证书
从xcode3时代习惯了手动选择证书,即 Provisioning Profile和 Code Signing Identify. 而随着团队扩大,应用量增多,需要管理的证书也越来越多,每次从长长的l ...
- [BUAA_SE_2017]个人项目-Sudoku
个人项目作业-数独 Github项目地址 时间预估 PSP2.1 Personal Software Process Stages 预估时间(分钟) 实际耗时(分钟) Planning 计划 60 · ...