洛谷 P3224 [HNOI2012]永无乡
题面
永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 \(1\) 到 \(n\) 来表示。某些岛之间由巨大的桥连接,通过桥可以从一个岛到达另一个岛。如果从岛 \(a\) 出发经过若干座(含 \(0\) 座)桥可以 到达岛 \(b\) ,则称岛 \(a\) 和岛 \(b\) 是连通的。
现在有两种操作:
B x y 表示在岛 \(x\) 与岛 \(y\) 之间修建一座新桥。
Q x k 表示询问当前与岛 \(x\) 连通的所有岛中第 \(k\) 重要的是哪座岛,即所有与岛 \(x\) 连通的岛中重要度排名第 \(k\) 小的岛是哪座,请你输出那个岛的编号。
题解
为什么我的\(splay\)这么慢?
线段树合并好像可以做
不过练练平衡树合并也行
合并时启发式合并
复杂度\(O(nlog^2n)\)
Code
#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
struct node {
	int ch[2], v, f, s, id;
}t[N*30];
int root[N], tot;
void pushup(int x) {
	t[x].s = t[t[x].ch[0]].s + t[t[x].ch[1]].s + 1;
}
void rotate(int x) {
	int y = t[x].f, z = t[y].f, k = t[y].ch[1] == x;
	t[z].ch[t[z].ch[1] == y] = x; t[x].f = z;
	t[y].ch[k] = t[x].ch[k^1]; t[t[x].ch[k^1]].f = y;
	t[y].f = x; t[x].ch[k^1] = y;
	pushup(y);
}
void splay(int x, int goal, int k) {
	while (t[x].f != goal) {
		int y = t[x].f, z = t[y].f;
		if (z != goal)
			(t[y].ch[1] == x) ^ (t[z].ch[1] == y) ? rotate(x) : rotate(y);
		rotate(x);
	}
	pushup(x);
	if (!goal) root[k] = x;
}
void insert(int k, int x, int id) {
	int now = root[k], f = 0;
	while (now) f = now, now = t[now].ch[x > t[now].v];
	now = ++tot;
	t[f].ch[x > t[f].v] = now;
	t[now].f = f; t[now].v = x; t[now].id = id;
	splay(now, 0, k);
}
int kth(int k, int x) {
	int now = root[k];
	while (1) {
		int ls = t[now].ch[0], rs = t[now].ch[1];
		if (t[ls].s >= x) now = ls;
		else if (t[ls].s + 1 < x) now = rs, x -= (t[ls].s + 1);
		else return t[now].id;
	}
}
int n, m;
int fa[N], a[N];
int find(int x) {
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}
void dfs(int x, int y) {
	insert(x, t[y].v, t[y].id);
	if (t[y].ch[0]) dfs(x, t[y].ch[0]);
	if (t[y].ch[1]) dfs(x, t[y].ch[1]);
	return ;
}
void merge(int a, int b) {
	if (a == b) return ;
	if (t[root[a]].s < t[root[b]].s) swap(a, b);
	fa[b] = a;
	dfs(a, root[b]);
}
void deb(int x) {
	if (t[x].ch[0]) deb(t[x].ch[0]);
	printf("%d ", t[x].v);
	if (t[x].ch[1]) deb(t[x].ch[1]);
}
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++) fa[i] = i, scanf("%d", &a[i]);
	for (int i = 1; i <= m; i++) {
		int x, y;
		scanf("%d%d", &x, &y);
		x = find(x), y = find(y);
		fa[y] = x;
	}
	for (int i = 1; i <= n; i++) {
		int x = find(i);
		insert(x, a[i], i);
	}
	int Q;
	scanf("%d", &Q);
	while (Q--) {
		char c; int a, b;
		cin >> c >> a >> b;
		if (c == 'Q') {
			a = find(a);
			/*printf("test : ");
			deb(root[a]);
			printf("\n");*/
			if (t[root[a]].s < b) puts("-1");
			else printf("%d\n", kth(a, b));
		}
		else {
			a = find(a), b = find(b);
			merge(a, b);
		}
	}
	return 0;
}
												
											洛谷 P3224 [HNOI2012]永无乡的更多相关文章
- 洛谷 P3224 [HNOI2012]永无乡 解题报告
		
P3224 [HNOI2012]永无乡 题目描述 永无乡包含 \(n\) 座岛,编号从 \(1\) 到 \(n\) ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 \(n\) 座岛排名,名次用 ...
 - 洛谷P3224 [HNOI2012]永无乡(线段树合并+并查集)
		
题目描述 永无乡包含 nnn 座岛,编号从 111 到 nnn ,每座岛都有自己的独一无二的重要度,按照重要度可以将这 nnn 座岛排名,名次用 111 到 nnn 来表示.某些岛之间由巨大的桥连接, ...
 - [洛谷P3224][HNOI2012]永无乡
		
题目大意:给你$n$个点,每个点有权值$k$,现有两种操作: 1. $B\;x\;y:$将$x,y$所在联通块合并2. $Q\;x\;k:$查询第$x$个点所在联通块权值第$k$小是哪个数 题解:线段 ...
 - 2018.08.11 洛谷P3224 [HNOI2012]永无乡(线段树合并)
		
传送门 给出n个带点权的点,支持连边和查询连通块第k大. 这个貌似就是一道线段树合并的裸板啊... 代码: #include<bits/stdc++.h> #define N 100005 ...
 - 【洛谷P3224】永无乡 并查集+Splay启发式合并
		
题目大意:给定 N 个点的图,点有点权,初始有一些无向边,现在有 Q 个询问,每个询问支持动态增加一条无向边连接两个不连通的点和查询第 X 个点所在的联通块中权值第 K 大的是哪个点. 题解:学会了平 ...
 - 洛谷.3224.[HNOI2012]永无乡(Splay启发式合并)
		
题目链接 查找排名为k的数用平衡树 合并时用启发式合并,把size小的树上的所有节点插入到size大的树中,每个节点最多需要O(logn)时间 并查集维护连通关系即可 O(nlogn*insert t ...
 - 线段树合并+并查集 || BZOJ 2733: [HNOI2012]永无乡 || Luogu P3224 [HNOI2012]永无乡
		
题面:P3224 [HNOI2012]永无乡 题解: 随便写写 代码: #include<cstdio> #include<cstring> #include<iostr ...
 - P3224 [HNOI2012]永无乡 题解
		
P3224 [HNOI2012]永无乡 题解 题意概括 有若干集合,每个集合最初包含一个值,和一个编号1~n.两个操作:合并两个集合,查询包含值x的集合中第k大值最初的集合编号. 思路 维护集合之间关 ...
 - bzoj2733 / P3224 [HNOI2012]永无乡(并查集+线段树合并)
		
[HNOI2012]永无乡 每个联通块的点集用动态开点线段树维护 并查集维护图 合并时把线段树也合并就好了. #include<iostream> #include<cstdio&g ...
 
随机推荐
- Java泛型中的通配符
			
Java泛型中的通配符可以直接定义泛型类型的参数.而不用把该函数定义成泛型函数. public class GenericsTest { public static void main(String[ ...
 - 关于C++中不同类之间的赋值问题——存疑
			
operator=不能重载为全局函数.理由如下 void operator=(int i , A& a) { a.a = i } ; 那么将会出现 99 = a 这种代码,但是99不是左值, ...
 - 二项分布&超几何分布
			
伯努利分布 在一次试验中,事件A出现的概率为p,不出现的概率为q=1-p.若以β记事件A出现的次数,则β仅取0,1两值,相应的概率分布为: 二项分布是指在只有两个结果的n次独立的伯努利试验中,所期望 ...
 - WireShark抓包的pcap文件格式分析
			
http://www.360doc.com/content/14/0220/11/15257968_354157537.shtml http://www.360doc.com/content/14/0 ...
 - Spring框架总结(五)
			
自动装配(了解) 根据名称自动装配:autowire="byName" 自动去IOC容器中找与属性名同名的引用的对象,并自动注入 延续使用user.dao.service.acti ...
 - javascript总结38: 神奇的this
			
1 this的特性 this 是在函数中的 this 的指向 是在函数调用的时候决定的 this的指向. 谁调用这个函数,函数中的this就指向谁 function fn (){ console.lo ...
 - ecshop后台登录频繁自动退出问题终极解决方法集锦
			
ecshop后台登录后,有时候会自动退出,而且还会很频繁,有的是后台操作两下就莫名退出了,有的是恰好三分钟左右登出.这让管理员很恼火,严重影响了后台使用.对于这一问题,网络上可给的解决方法各有不同.千 ...
 - Web图片编辑控件发布-Xproer.ImageEditor
			
版权所有 2009-2014 荆门泽优软件有限公司 保留所有权利 官方网站:http://www.ncmem.com 产品首页:http://www.ncmem.com/webplug/image-e ...
 - [Lua快速了解一下]Lua的MetaTable和MetaMethod
			
MetaTable和MetaMethod是Lua中的重要的语法,MetaTable主要是用来做一些类似于C++重载操作符式的功能. 两个分数 fraction_a = {numerator=, den ...
 - 通过python实现wc基本功能
			
---恢复内容开始--- 1.Github项目地址: https://github.com/zhg1998/ww/blob/master/wc.py 2.项目相关要求: 写一个命令行程序,模仿已有wc ...