传送门

题目分析

  起初每个岛都是一个平衡树, 并查集的祖先都是自己。合并两岛时,pri较小的祖先会被作为合并后的祖先, 而两颗平衡树采用启发式合并。查询k值就是基本操作。

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std; const int N = 1e5 + ;
int n, m;
#define SZ(x) (x?x->sze:0)
struct node{
node *lc, *rc;
int pri, sze, val, num;
inline node* upt(){
sze = SZ(lc) + SZ(rc) + ;
return this;
}
}pool[N], *tail = pool, *nod[N];
int fa[N]; inline int Rand(){
static int RAND_VAL = ;
return RAND_VAL += RAND_VAL << | ;
} inline node* newNode(int v, int k){
node *x = ++tail;
x->sze = , x->val = v, x->pri = Rand(), x->num = k;
return x;
} inline node* Merge2(node *u, node *v){
if(!u) return v;
if(!v) return u;
if(u->pri < v->pri){
u->rc = Merge2(u->rc, v);
return u->upt();
}
else{
v->lc = Merge2(u, v->lc);
return v->upt();
}
} inline int getAnc(int a){
return fa[a] == a ? a : (fa[a] = getAnc(fa[a]));
} inline void Split_v(node *u, int v, node *&x, node *&y){
if(!u){
x = y = NULL;
return;
}
if(u->val <= v){
Split_v(u->rc, v, x, y);
u->rc = NULL, u->upt();
x = Merge2(u, x);
}
else{
Split_v(u->lc, v, x, y);
u->lc = NULL, u->upt();
y = Merge2(y, u);
}
} inline void Split_k(node *u, int k, node *&x, node *&y){
if(!u){
x = y = NULL;
return;
}
if(SZ(u->lc) < k){
Split_k(u->rc, k - SZ(u->lc) - , x, y);
u->rc = NULL, u->upt();
x = Merge2(u, x);
}
else{
Split_k(u->lc, k, x, y);
u->lc = NULL, u->upt();
y = Merge2(y, u);
}
} inline node* Merge(node *u, node *v){
if(!u) return v;
if(!v) return u;
node *L, *R;
if(u->pri > v->pri) swap(u, v);
Split_v(v, u->val, L, R);
u->lc = Merge(u->lc, L);
u->rc = Merge(u->rc, R);
return u->upt();
} inline int read(){
int i = , f = ; char ch = getchar();
for(; (ch < '' || ch > '') && ch != '-'; ch = getchar());
if(ch == '-') f = -, ch = getchar();
for(; ch >= '' && ch <= ''; ch = getchar())
i = (i << ) + (i << ) + (ch - '');
return i * f;
} inline void wr(int x){
if(x < ) putchar('-'), x = -x;
if(x > ) wr(x / );
putchar(x % + '');
} int main(){
n = read(), m = read();
for(int i = ; i <= n; i++) fa[i] = i;
for(int i = ; i <= n; i++) nod[i] = newNode(read(), i);
for(int i = ; i <= m; i++){
int a = read(), b = read();
int fu = getAnc(a), fv = getAnc(b);
if(fu != fv){
if(nod[fu]->pri < nod[fv]->pri) fa[fv] = fu, nod[fu] = Merge(nod[fu], nod[fv]);
else fa[fu] = fv, nod[fv] = Merge(nod[fu], nod[fv]);
}
}
// for(int i = 1; i <= n; i++) cout<<i<<":"<<nod[i]->sze<<endl;
int Q = read();
for(int i = ; i <= Q; i++){
char opt[]; scanf("%s", opt);
if(opt[] == 'Q'){
node *L, *R, *p, *q;
int x = read(), k = read(), fx = getAnc(x);
// cout<<x<<" "<<k<<" "<<fx<<" "<<endl;
Split_k(nod[fx], k - , L, R);
Split_k(R, , p, q);
if(p) wr(p->num);
else wr(-);
putchar('\n');
nod[fx] = Merge2(L, Merge2(p, q));
}
else{
int a = read(), b = read();
int fu = getAnc(a), fv = getAnc(b);
if(fu != fv){
if(nod[fu]->pri < nod[fv]->pri) fa[fv] = fu, nod[fu] = Merge(nod[fu], nod[fv]);
else fa[fu] = fv, nod[fv] = Merge(nod[fu], nod[fv]);
}
}
}
return ;
}

【bzoj2733】永无乡(无旋treap启发式合并 + 并查集)的更多相关文章

  1. BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)

    不难...treap + 启发式合并 + 并查集 搞搞就行了 --------------------------------------------------------------------- ...

  2. 【BZOJ2733】永无乡[HNOI2012](splay启发式合并or线段树合并)

    题目大意:给你一些点,修改是在在两个点之间连一条无向边,查询时求某个点能走到的点中重要度第k大的点.题目中给定的是每个节点的排名,所以实际上是求第k小:题目求的是编号,不是重要度的排名.我一开始差点被 ...

  3. bzoj2733 永无乡 splay树的启发式合并

    https://vjudge.net/problem/HYSBZ-2733 给一些带权点,有些点是互相连通的, 然后给出2种操作,在两点间加一条边,或者询问一个点所在的连通块内的第k小值的编号 并查集 ...

  4. 【HNOI2012】永无乡(splay,启发式合并)

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

  5. [HNOI2012] 永无乡 解题报告 (splay+启发式合并)

    题目链接:https://www.luogu.org/problemnew/show/P3224#sub 题目: 题目大意: 维护多个联通块,没有删除操作,每次询问某一联通块的第k大 解法: 维护联通 ...

  6. 【洛谷 P3224】 [HNOI2012]永无乡(Splay,启发式合并)

    题目链接 启发式合并就是暴力合并把小的合并到大的里,一个一个插进去. 并查集维护连通性,同时保证并查集的根就是所在Splay的根,这样能省去很多操作. #include <cstdio> ...

  7. BZOJ 2733 [HNOI2012]永无乡 (权值线段树启发式合并+并查集)

    题意: n<=1e5的图里,在线连边.查询某连通块第k大 思路: 练习线段树合并的好题,因为依然记得上一次启发式合并trie的时候内存爆炸的恐怖,所以这次还是用了动态开点.回收 听说启发式合并s ...

  8. 【20181026T2】**图【最小瓶颈路+非旋Treap+启发式合并】

    题面 [错解] 最大最小?最小生成树嘛 蛤?还要求和? 点分治? 不可做啊 写了个MST+暴力LCA,30pts,140多行 事后发现30分是给dijkstra的 woc [正解] 树上计数问题:①并 ...

  9. BZOJ 3545: [ONTAK2010]Peaks( BST + 启发式合并 + 并查集 )

    这道题很好想, 离线, 按询问的x排序从小到大, 然后用并查集维护连通性, 用平衡树维护连通块的山的权值, 合并就用启发式合并.时间复杂度的话, 排序是O(mlogm + qlogq), 启发式合并是 ...

随机推荐

  1. BingMap频繁Add Pushpin和Delete Pushpin会导致内存泄露

    近期在做性能測试的时候发现BingMap内存泄露(memory leak)的问题,查找了一些国外的帖子,发现也有类似的问题,可是没有好的解决的方法. https://social.msdn.micro ...

  2. amazeui学习笔记--css(常用组件6)--图标Icon

    amazeui学习笔记--css(常用组件6)--图标Icon 一.总结 1.关注用法即可:在 HTML 上添加添加 am-icon-{图标名称} class. <span class=&quo ...

  3. Android Set与List之间转化

    List list = new ArrayList(set); Set set = new HashSet(list); //但是有一点,转换当中可能要丢失数据,尤其是从list转换到set的时候,因 ...

  4. [转]C#连接操作mysql实例

    本文转自:http://hi.baidu.com/zhqngweng/item/c4d2520cb7216877bfe97edf 第三方组件:Mysql.Data.dll说明:去官方网站下载Mysql ...

  5. centos7 分区满了,分析哪个目录或文件占用空间-小叶-51CTO博客

    原文:centos7 分区满了,分析哪个目录或文件占用空间-小叶-51CTO博客 du -sh 例如: [root@zabbix ~]# du -sh /var/* 0 /var/adm 132M / ...

  6. 微信小程序踩坑- tabBar.list[3].selectedIconPath 大小超过 40kb

    重新启动微信小程序编辑器的时候遇到了这样的一个问题: tabBar.list[3].selectedIconPath 大小超过 40kb 微信小程序开发的过程之中总会出现这样或者那样的错误,需要我们耐 ...

  7. Maven 异常:Project configuration is not up-to-date with pom.xml解决方案

    一.异常信息: 导入maven工程后,出现如下错误: Description    Resource    Path    Location    TypeProject configuration ...

  8. C API函数描写叙述(S-W)

    25.2.3.59. mysql_select_db() int mysql_select_db(MYSQL *mysql, const char *db) 描写叙述 使由db指定的数据库成为由mys ...

  9. java.util.logging使用笔记2

      java.util.logging是java自带的日志处理系统,其功能不如log4j/logback强大,但可以完成基本的日志需求. 另外,如果在一个项目中使用log4j, 而这个项目引用的第3方 ...

  10. 在此页上的 ActiveX 控件和本页上的其它部份的交互可能不安全

    版权声明:转载时请以超链接形式标明文章原始出处和作者信息http://xqy266.blogbus.com/logs/66258230.html 在EOS6的项目中,如果采用VC++开发的Active ...