BZOJ 3551: [ONTAK2010]Peaks加强版

如果知道kruskal重构树这个东西就很简单了。
kruskal重构树就是kruskal的过程中,不直接连 \((u, v)\),而是新建一个节点作为 \(u\)\(v\) 的父亲,并且边权赋在这个点上
这样就得到一棵二叉树(或者森林)
有大根堆的性质
然后倍增预处理祖先,每次询问就是跑到最高的一个祖先,且点权不大于 \(x\)
这个时候子树里面的所有点就是权值不大于 \(x\),且与 \(v\) 相连的连通块了
查询子树k大就转dfs序+主席树即可

#include <bits/stdc++.h>
#define lp tree[p].l
#define rp tree[p].r
#define rq tree[q].r
#define lq tree[q].l
#define mid ((l + r) >> 1)

char buf[1 << 21], *p1 = buf, *p2 = buf;
inline char getc() {
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++;
}
inline int read() {
	int x = 0, f = 1; char ch = getc();
	while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getc(); }
	while (ch >= '0' && ch <= '9') { x = x * 10 + ch - 48; ch = getc(); }
	return x * f;
}

const int N = 2e5 + 7;
struct Edge {
	int u, v, c;
	void in() { u = read(), v = read(), c = read(); }
	bool operator < (const Edge &p) const { return c < p.c; }
} edge[N * 3];
struct Node {
	int l, r, sum;
} tree[N * 20];

int pa[N];
int n, m, h[N], w[N], q, root[N], tol, fa[N][19], c[N], all;
int head[N], cnt = 1, to[N], ne[N], node, in[N], out[N], dfn;
inline void add(int u, int v) {
	to[++cnt] = v; ne[cnt] = head[u]; head[u] = cnt;
}
int find(int x) { return x == pa[x] ? x : pa[x] = find(pa[x]); }

void update(int &p, int q, int l, int r, int pos) {
	tree[p = ++tol] = tree[q];
	tree[p].sum++;
	if (l == r) return;
	if (pos <= mid) update(lp, lq, l, mid, pos);
	else update(rp, rq, mid + 1, r, pos);
}
int query(int p, int q, int l, int r, int k) {
	if (l == r) return l;
	int t = tree[rp].sum - tree[rq].sum;
	if (t >= k) return query(rp, rq, mid + 1, r, k);
	return query(lp, lq, l, mid, k - t);
}
void kruskal() {
	for (int i = 1; i <= 2 * n; i++) pa[i] = i;
	std::sort(edge + 1, edge + 1 + m);
	for (int i = 1; i <= m; i++) {
		int u = find(edge[i].u), v = find(edge[i].v);
		if (u == v) continue;
		int node = ++n;
		pa[u] = pa[v] = node;
		c[node] = edge[i].c;
		fa[u][0] = fa[v][0] = node;
		add(node, u); add(node, v);
	}
}
void dfs(int u) {
	in[u] = ++dfn;
	update(root[dfn], root[dfn - 1], 0, all, h[u]);
	for (int i = 1; i <= 18; i++)
		fa[u][i] = fa[fa[u][i - 1]][i - 1];
	for (int i = head[u]; i; i = ne[i]) {
		int v = to[i];
		dfs(v);
	}
	out[u] = dfn;
}
int findrt(int u, int x) {
	for (int i = 18; ~i; i--)
		if (fa[u][i] && c[fa[u][i]] <= x)
			u = fa[u][i];
	return u;
}

int main() {
	//freopen("ans.out", "w", stdout);
	n = read(), m = read(), q = read();
	for (int i = 1; i <= n; i++)
		h[i] = w[i] = read();
	std::sort(w + 1, w + 1 + n);
	all = std::unique(w + 1, w + 1 + n) - w - 1;
	for (int i = 1; i <= n; i++)
		h[i] = std::lower_bound(w + 1, w + 1 + all, h[i]) - w;

	for (int i = 1; i <= m; i++) edge[i].in();
	kruskal();

	for (int i = n; i >= 1; i--)
		if (!fa[i][0])
			dfs(i);
	int ans = 0;
	for (int u, x, k; q--; ) {
		u = read(), x = read(), k = read();
		u ^= ans, x ^= ans, k ^= ans;
		u = findrt(u, x);
		if (out[u] - in[u] + 1 < k) {
			ans = 0;
			puts("-1");
			continue;
		}
		ans = query(root[out[u]], root[in[u] - 1], 0, all, k);
		if (ans == 0) puts("-1");
		else printf("%d\n", ans = w[ans]);
	}
	return 0;
}
posted @ 2020-02-18 17:27  Mrzdtz220  阅读(98)  评论(0)    收藏  举报