洛谷 P4197 Peaks

原题链接

tag :kruskal重构树 + 树上倍增 + 主席树

学习kruskal重构树推荐看这篇
Kruskal重构树入门 - 自为风月马前卒

其实重构树的核心代码很短:

rep (i, 1, m) {
		int pu = find(EG[i].u), pv = find(EG[i].v);
		if (pu == pv) continue;
		now++;
		fa[now] = fa[pu] = fa[pv] = now;
		h[now] = EG[i].w;
		add(now, pu), add(now, pv);
	}

就是把将要合并两点的连边断开,新增一个点分别连向这两点,新增点的点权即为断开的边的边权
有很多优秀的性质:
1、是一棵二叉树
2、按照最小生成树建立,则是大根堆
3、任意两点之间的边权最大值为它们的lca

#include<bits/stdc++.h>
using namespace std;

#define fr first
#define se second
#define et0 exit(0);
#define rep(i, a, b) for(int i = (int)(a); i <= (int)(b); i ++)
#define rrep(i, a, b) for(int i = (int)(a); i >= (int)(b); i --)
#define IO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);

typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
typedef unsigned long long ULL;

const int INF = 0X3f3f3f3f, N = 1e5 + 10, M = 5e5 + 10, MOD = 1e9 + 7;
const double eps = 1e-7, pi = acos(-1);

int n, m, Q;
int now;
int h[N << 1], fa[N << 1];
int lg[N << 1], Fa[N << 1][30], dep[N << 1];
int id, leaf_id[N];

PII rng[N << 1];

vector<int> vc;

struct Egde {
	int u, v;
	int w;
} EG[M];

int head[N << 1], idx;

struct EGDE {
	int to, next;
} eg[M << 1];

void add(int x, int y) {
	eg[idx].to = y;
	eg[idx].next = head[x];
	head[x] = idx++;
}

bool cmp(Egde x, Egde y) {
	return x.w < y.w;
}

int find(int x) {
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}

int find_vc(int x) {
	x = -x;
	return lower_bound(vc.begin(), vc.end(), x) - vc.begin();
}

void Init_lg() { // lg预处理
	for (int i = 1; i <= N; i++) lg[i] = lg[i - 1] + (1 << lg[i - 1] == i);
}

int dfs(int u, int f) {
	bool is_leaf = true;

	Fa[u][0] = f;
	dep[u] = dep[f] + 1;
	for (int i = 1; i <= lg[dep[u]]; i++) Fa[u][i] = Fa[Fa[u][i - 1]][i - 1];

	for (int i = head[u]; ~i; i = eg[i].next) {
		int to = eg[i].to;
		if (to == f) continue;

		is_leaf = false;

		int t = dfs(to, u);
		if (t) {
			if (!rng[u].fr) rng[u].fr = t;
			else rng[u].se = t;
		}
		else {
			if (!rng[u].fr) rng[u].fr = rng[to].fr;
			else rng[u].se = rng[to].se;
		}
	}
	if (is_leaf) {
		leaf_id[++id] = u;
		vc.push_back(-h[u]);
		return id;
	} else return 0;
}

int find_h(int u, int x) { //倍增
	u = Fa[u][0];
	if (h[u] > x) return -1;

	rrep (j, 18, 0)
	if (Fa[u][j] && h[Fa[u][j]] <= x) u = Fa[u][j];

	return u;
}

struct NODE {
	int l, r;
	int cnt;
} tr[N * 4 + N * 21];

int root[N];

int build(int l, int r) {
	int q = ++idx;
	if (l == r) return q;
	else {
		int mid = l + r >> 1;
		tr[q].l = build(l, mid);
		tr[q].r = build(mid + 1, r);
		return q;
	}
}

int insert(int p, int l, int r, int x) {
	int q = ++idx;
	tr[q] = tr[p];
	if (l == r) {
		tr[q].cnt++;
		return q;
	} else {
		int mid = l + r >> 1;
		if (x <= mid) tr[q].l = insert(tr[p].l, l, mid, x);
		else tr[q].r = insert(tr[p].r, mid + 1, r, x);
		tr[q].cnt = tr[tr[q].l].cnt + tr[tr[q].r].cnt;
		return q;
	}
}

int query(int p, int q, int l, int r, int k) {
	if (l == r) return l;
	else {
		int mid = l + r >> 1;
		int cnt = tr[tr[q].l].cnt - tr[tr[p].l].cnt;
		if (cnt >= k) return query(tr[p].l, tr[q].l, l, mid, k);
		else return query(tr[p].r, tr[q].r, mid + 1, r, k - cnt);
	}
}

void work() {
	Init_lg();
	memset(head, -1, sizeof head);

	scanf("%d%d%d", &n, &m, &Q);
	rep (i, 1, n) scanf("%d", &h[i]);
	rep (i, 1, m) scanf("%d%d%d", &EG[i].u, &EG[i].v, &EG[i].w);
	sort(EG + 1, EG + 1 + m, cmp);

	//kruskal重构树
	now = n;
	rep (i, 1, n) fa[i] = i;
	rep (i, 1, m) {
		int pu = find(EG[i].u), pv = find(EG[i].v);
		if (pu == pv) continue;
		now++;
		fa[now] = fa[pu] = fa[pv] = now;
		h[now] = EG[i].w;
		add(now, pu), add(now, pv);
	}
	
	dfs(now, 0);

	sort(vc.begin(), vc.end());
	vc.erase(unique(vc.begin(), vc.end()), vc.end());
	
	int vs = vc.size();
	idx = 0, root[0] = build(0, vs - 1);
	rep (i, 1, n) root[i] = insert(root[i - 1], 0, vs - 1, find_vc(h[leaf_id[i]]));

	while (Q--) {
		int u, x, k;
		scanf("%d%d%d", &u, &x, &k);
		
		int v = find_h(u, x);
		if (v == -1 || rng[v].se - rng[v].fr + 1 < k) cout << -1 << endl;
		else printf("%d\n", -vc[query(root[rng[v].fr - 1], root[rng[v].se], 0, vs - 1, k)]);
	}
}

signed main() {
//	IO

	int test = 1;
//	cin >> test;

	while (test--) {
		work();
	}

	return 0;
}
posted @ 2022-08-15 00:32  xhy666  阅读(20)  评论(0编辑  收藏  举报