【洛谷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 洛谷 题解 考虑离线做法,逆序处理,一个一个星球的加入.用并查集维护一下连通性就好了. 具体来说,先将被消灭的星球储存下来,先将没有被消灭的星球用并查集并在一起,这样做可以路径压缩,然 ...
随机推荐
- jenkins中配置svn 出现absolute path is not allowed
代码: 兵马未动,粮草先行 作者: 传说中的汽水枪 如有错误,请留言指正,欢迎一起探讨. 转载请注明出处. 想用jenkins作自动化部署tomcat. svn代码已经checkout到本地目录了(/ ...
- linux内核分析第四次实验
实验步骤: 使用库函数API和C代码中嵌入汇编代码两种方式使用同一个系统调用.本次实验中我使用第20号系统调用getpid()函数,用于取得进程识别码. C代码(getpid.c): #include ...
- Oracle系列(一): Oracle数据恢复
Oracle数据恢复 在使用Oracle的时候,突然一部小心update或者delete全部数据后怎么办? select * from table as of timestamp to_timest ...
- Glace:generator-jhipster, adding User entity enhancement management
https://github.com/jhipster/generator-jhipster/issues/2538 jhipster,很好用的开发工具.国外知名度高,国内未普及,国外大公司在用. j ...
- Eclipse: Difference between clean, build and publish
https://stackoverflow.com/questions/5656989/eclipse-difference-between-clean-build-and-publish http: ...
- [转载]Memory Limits for Windows and Windows Server Releases
Memory Limits for Windows and Windows Server Releases This topic describes the memory limits for sup ...
- vCenter简单查看多少虚拟机在开机状态和一共多少虚拟机
vCenter 界面上面不好找 具体的开机 运行数目 但是数据库里面比较好差 登录vCenter的数据库. 查看表主要是 查看正在开机的虚拟机 select * from dbo.VPX_VM WHE ...
- []转帖] 浅谈Linux下的五种I/O模型
浅谈Linux下的五种I/O模型 https://www.cnblogs.com/chy2055/p/5220793.html 一.关于I/O模型的引出 我们都知道,为了OS的安全性等的考虑,进程是 ...
- Java和Android的Lru缓存,及其实现原理
一.概述 Android提供了LRUCache类,可以方便的使用它来实现LRU算法的缓存.Java提供了LinkedHashMap,可以用该类很方便的实现LRU算法,Java的LRULinkedHas ...
- rabbitmq使用报错总结
最近公司重构服务器架构,需要用到rabbitmq,在公司搞了一个下午还是连接不上,后来细看了英文说明,测试连接成功,得出如下报错几点. 我用的安装包:otp_win64_21.3.exe(erlang ...