P3224 [HNOI2012]永无乡 题解

solution

由于出现了 询问当前与岛 x 连通的所有岛 所以考虑并查集加线段树合并。

  1. B 操作:相当于将岛 \(x\) 所在的线段树和岛 \(y\) 所在的线段树合并,注意判断 \(x\)\(y\) 是否在同一集合。
  2. Q 操作:权值线段树基本操作,从岛 \(x\) 所在的根节点向下递归,若 \(sum_{lift}\le k\),则向左子树查找第 \(k\) 小;若 \(sum_{lift}>k\) 则向右子树查找第 \(k-sum_{lift}\) 小。

code

#include <bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define I inline
#define ll long long
#define CI const int
#define RI register int
#define W while
#define gc getchar
#define D isdigit(c=gc())
#define max(x,y) ((x)>(y)?(x):(y))
#define min(x,y) ((x)<(y)?(x):(y))
#define ms(a,x) memset((a),(x),sizeof(a))
using namespace std;
namespace SlowIO {
	I void readc (char& c) {W (isspace (c = gc ()));}
	Tp I void read (Ty& x) {char c; int f = 1; x = 0; W (! D) f = c ^ '-' ? 1 : -1; W (x = (x * 10) + (c ^ 48), D); x *= f;}
	Ts I void read (Ty& x, Ar&... y) {read (x); read (y...);}
} using namespace SlowIO;
CI N = 1e5, N4 = 5e6; int sum[N4 + 5], sl[N4 + 5], sr[N4 + 5], tg[N4 + 5], fa[N + 5], rt[N4 + 5], ntot = 0, n, m; char opt[5];
int find (int x) {return fa[x] == x ? x : fa[x] = find (fa[x]);}
void unionn (int x, int y) {x = find (x); y = find (y); fa[y] = x;}
void pushup (int root) {sum[root] = sum[sl[root]] + sum[sr[root]];}
void update (int &root, int L, int R, int pos, int x) {
	if (! root) root = ++ ntot; if (L == R) {++ sum[root]; tg[root] = x; return ;} int mid = (L + R) >> 1;
	if (pos <= mid) update (sl[root], L, mid, pos, x); else update (sr[root], mid + 1, R, pos, x); pushup (root);
}
int merge (int a, int b, int L, int R) {
	if (! a || ! b) return a + b; if (L == R) {if (tg[b]) sum[a] += sum[b], tg[a] = tg[b]; return a;} int mid = (L + R) >> 1;
	sl[a] = merge (sl[a], sl[b], L, mid); sr[a] = merge (sr[a], sr[b], mid + 1, R); pushup (a); return a;
}
int query (int root, int L, int R, int k) { // 查询第 k 小
	if (sum[root] < k || ! root) return -1; if (L == R) return tg[root]; int mid = (L + R) >> 1;
	if (sum[sl[root]] >= k) return query (sl[root], L, mid, k); else return query (sr[root], mid + 1, R, k - sum[sl[root]]);
}
int main () {
	RI i, j; read (n, m); for (i = 1; i <= n; ++ i) fa[i] = rt[i] = i, ++ ntot; for (i = 1; i <= n; ++ i) {int x; read (x); update (rt[i], 1, n, x, i);}
	for (i = 1; i <= m; ++ i) {int u, v; read (u, v); if (find (u) != find (v)) u = find (u), v = find (v), rt[u] = merge (rt[u], rt[v], 1, n), unionn (u, v);}
	int k; read (k); W (k --) {	
		char ch; int x, y; scanf ("%s", opt); read (x, y); if (opt[0] == 'Q') {
			int ans = query (rt[find (x)], 1, n, y); printf ("%d\n", ans);
		} else {if (find (x) != find (y)) x = find (x), y = find (y), rt[x] = merge (rt[x], rt[y], 1, n), unionn (x, y);}
	}
	return 0;
}
posted @ 2022-08-21 22:52  ClapEcho233  阅读(9)  评论(0编辑  收藏  举报