「BZOJ 2733」「HNOI 2012」永无乡「启发式合并」
题意
你需要维护若干连通快,有两个操作
- 合并\(x,y\)所在的连通块
- 询问\(x\)所在连通块中权值从小到大排第\(k\)的结点编号
题解
可以启发式合并\(splay\),感觉比较好些的
一个连通块就是一个\(splay\),每次合并挑小的\(splay\)遍历一遍把点按中序遍历存下来,然后一个一个插入大的\(splay\)就行了;查询就是\(splay\)的\(kth\)操作
这样时间复杂度\(O(n \log n)\),它的证明可以见2018论文集 :董炜隽《浅谈Splay与Treap的性质及其应用》,其中有提一个\(\text{Dynamic Finger Theorem}\)
(其实随便插入的话是两个\(\log\),也能通过,十分玄学)
#include <algorithm>
#include <cstdio>
#include <vector>
using namespace std;
const int N = 2e5 + 10;
int n, m, q, bel[N], rt[N], w[N];
int ch[N][2], fa[N], sz[N];
void upd(int u) { sz[u] = sz[ch[u][0]] + sz[ch[u][1]] + 1; }
int dir(int u) { return ch[fa[u]][1] == u; }
void rotate(int u) {
int d = dir(u), f = fa[u];
if(fa[u] = fa[f]) ch[fa[u]][dir(f)] = u;
if(ch[f][d] = ch[u][d ^ 1]) fa[ch[f][d]] = f;
fa[ch[u][d ^ 1] = f] = u;
upd(f); upd(u);
}
void ins(int &rt, int u, int f = 0) {
if(!rt) {
rt = u; fa[u] = f; sz[u] = 1;
ch[u][0] = ch[u][1] = 0;
return ;
}
ins(ch[rt][w[u] > w[rt]], u, rt);
upd(rt);
}
void splay(int u) {
for(; fa[u]; rotate(u)) if(fa[fa[u]])
rotate(dir(u) == dir(fa[u]) ? fa[u] : u);
rt[bel[u]] = u;
}
int kth(int u, int k) {
int v = u;
while(1) {
if(k <= sz[ch[v][0]]) v = ch[v][0];
else {
k -= sz[ch[v][0]] + 1;
if(k <= 0) break ;
v = ch[v][1];
}
}
splay(v);
return v;
}
int a[N], l;
void dfs(int u) {
if(u) {
dfs(ch[u][0]);
a[++ l] = u;
dfs(ch[u][1]);
}
}
void link(int u, int v) {
u = bel[u]; v = bel[v];
if(u == v) return ;
if(sz[rt[u]] < sz[rt[v]]) swap(u, v);
l = 0; dfs(rt[v]);
for(int i = 1; i <= l; i ++) {
bel[a[i]] = u;
ins(rt[u], a[i]);
splay(a[i]);
}
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i ++) scanf("%d", w + i);
for(int i = 1; i <= n; i ++) {
bel[i] = rt[i] = i; sz[i] = 1;
}
int u, v;
for(int i = 1; i <= m; i ++) {
scanf("%d%d", &u, &v);
link(u, v);
}
scanf("%d", &q);
char op[5];
for(int i = 1; i <= q; i ++) {
scanf("%s%d%d", op, &u, &v);
if(* op == 'Q') {
u = rt[bel[u]];
if(v > sz[u]) puts("-1");
else printf("%d\n", kth(u, v));
}
if(* op == 'B') link(u, v);
}
return 0;
}
「BZOJ 2733」「HNOI 2012」永无乡「启发式合并」的更多相关文章
- 【BZOJ 2733】【HNOI 2012】永无乡 Splay启发式合并
启发式合并而已啦,, 调试时发现的错误点:insert后没有splay,把要拆开的树的点插入另一个树时没有把ch[2]和fa设为null,找第k大时没有先减k,,, 都是常犯的错误,比赛时再这么粗心就 ...
- BZOJ 2733: [HNOI2012]永无乡(treap + 启发式合并 + 并查集)
不难...treap + 启发式合并 + 并查集 搞搞就行了 --------------------------------------------------------------------- ...
- BZOJ 2733: [HNOI2012]永无乡 [splay启发式合并]
2733: [HNOI2012]永无乡 题意:加边,询问一个连通块中k小值 终于写了一下splay启发式合并 本题直接splay上一个节点对应图上一个点就可以了 并查集维护连通性 合并的时候,把siz ...
- BZOJ 2733 [HNOI2012]永无乡(启发式合并+Treap+并查集)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2733 [题目大意] 给出n个点,每个点都有自己的重要度,现在有连边操作和查询操作, 查 ...
- ☆ [HNOI2012] 永无乡 「平衡树启发式合并」
题目类型:平衡树启发式合并 传送门:>Here< 题意:节点可以连边(不能断边),询问任意两个节点的连通性与一个连通块中排名第\(k\)的节点 解题思路 如果不需要询问排名,那么并查集即可 ...
- bzoj 2733 : [HNOI2012]永无乡 (线段树合并)
Description 永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以 ...
- 2733: [HNOI2012]永无乡 线段树合并
题目: https://www.lydsy.com/JudgeOnline/problem.php?id=2733 题解: 建n棵动态开点的权值线段树,然后边用并查集维护连通性,边合并线段树维护第k重 ...
- bzoj 2733 永无乡 - 并查集 - 线段树
永无乡包含 n 座岛,编号从 1 到 n,每座岛都有自己的独一无二的重要度,按照重要度可 以将这 n 座岛排名,名次用 1 到 n 来表示.某些岛之间由巨大的桥连接,通过桥可以从一个岛 到达另一个岛. ...
- BZOJ 2733: [HNOI2012]永无乡 启发式合并treap
2733: [HNOI2012]永无乡 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://www.lydsy.com/JudgeOnline/pr ...
随机推荐
- Excel开发学习笔记:文件选择控件、查找匹配项、单元格格式及数据有效性
一个自用的基于excel的小工具. , ), .Cells(, )) sysKpiRow.Interior.ColorIndex = ).value = , ) ...
- Build Assetbundle出错:An asset is marked as dont save, but is included in the build
前天Build Assetbundle的时候出错了,导致打包失败,具体日志内容如下: An asset is marked as dont save, but is included in the b ...
- mybatis 动态sql语句(2)
什么是动态SQL MyBatis的一个强大特性之一通常是它的动态SQL能力.如果你有使用JDBC或其他相似框架的经验,你就明白条件串联SQL字符串在一起是多么地痛苦,确保不能忘了空格或者在列表的最后的 ...
- 自定义inputformat和outputformat
1. 自定义inputFormat 1.1 需求 无论hdfs还是mapreduce,对于小文件都有损效率,实践中,又难免面临处理大量小文件的场景,此时,就需要有相应解决方案 1.2 分析 小文件的优 ...
- leetcode905
vector<int> sortArrayByParity(vector<int>& A) { vector<int> EVEN;//偶数 vector&l ...
- leetcode421
public class Solution { public int FindMaximumXOR(int[] nums) { , mask = ; ; i >= ; i--) { mask = ...
- Android studio如何和VS的region一样折叠代码
相信用过VS的朋友都会经常有用到VS的region来折叠代码,非常方便.那么Android studio是否可以呢?当然可以. 选择代码,Ctrl + Alt + T 选择 第二项,这样就可以啦
- 在linux中read、write函数
read函数从打开的设备或文件中读取数据. #include<</span>unistd.h> ssize_t read(int fd, void *buf, size_t ...
- eclipse egit(分支管理 下)
在Git的分支merge中,不可能没有代码的冲突问题,特别在跟别人分工合作时.那该怎么解决? 1.新建一个conflict分支,在dev方法下添加一句 System.out.println(“Crea ...
- 用eclipse+svn插件,上传新项目到svn服务器
给定trunk路径,https://svn.ws.125089.com/public/nlp/3434index/IndexByModelSolr/trunk/. 其中自己的web项目名字是Index ...