【BZOJ3551】[ONTAK2010]Peaks加强版

【BZOJ3551】[ONTAK2010]Peaks加强版

题面

给你一个图,每次询问给定一个位置、长度和(k),问从这个点出发,只能经过不大于这个长度的边,到达的点中点权第(k)大的点权

图的规模:(10^5)

题解

考虑离线怎么做:

将所有询问存下来,按照边权排序

每次加边线段树合并查(kth)即可

然鹅:离线加边一时爽,强制在线火葬场。

我们考虑强制在线怎么做:

妈妈!!我会(Kruskal)重构树!!!

我们有(Kruskal)重构树(这里是(MST))的性质:深度越深,节点权值越小

可以二分一下最浅的权值小于等于(k)的点,那么直接在它子树内用主席树(kth)就行了

辣鸡bzoj,这题空间开得神他妈玄学,稍微变一点就会挂

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
using namespace std; 
inline int gi() {
	register int data = 0, w = 1;
	register char ch = 0;
	while (!isdigit(ch) && ch != '-') ch = getchar(); 
	if (ch == '-') w = -1, ch = getchar();
	while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
	return w * data; 
}
const int MAX_N = 2e5 + 5;
const int MAX_LOG_N = 17; 
struct Node { int ls, rs, v; } t[MAX_N * 25];
int tot, rt[MAX_N << 1]; 
void insert(int &o, int p, int l, int r, int pos) { 
	o = ++tot, t[o] = t[p], ++t[o].v; 
	if (l == r) return ; 
	int mid = (l + r) >> 1; 
	if (pos <= mid) insert(t[o].ls, t[p].ls, l, mid, pos); 
	else insert(t[o].rs, t[p].rs, mid + 1, r, pos); 
} 
int query(int v, int u, int l, int r, int k) { 
	if (l == r) return l; 
	int mid = (l + r) >> 1, res = t[t[u].ls].v - t[t[v].ls].v; 
	if (res >= k) return query(t[v].ls, t[u].ls, l, mid, k); 
	else return query(t[v].rs, t[u].rs, mid + 1, r, k - res); 
} 
struct Graph { int to, next; } e[MAX_N << 1]; int fir[MAX_N], e_cnt;
void clearGraph() { memset(fir, -1, sizeof(fir)); e_cnt = 0; } 
void Add_Edge(int u, int v) { e[e_cnt] = (Graph){v, fir[u]}, fir[u] = e_cnt++; } 
struct Edge { int u, v, w; } a[MAX_N << 2]; 
bool operator < (const Edge &l, const Edge &r) { return l.w < r.w; } 
int N, M, Q, h[MAX_N]; 
int pa[MAX_N], val[MAX_N]; 
int getf(int x) { return (x == pa[x]) ? x : (pa[x] = getf(pa[x])); } 
int fa[MAX_N][MAX_LOG_N], mx[MAX_N][MAX_LOG_N], p[MAX_N << 1], dep[MAX_N], top; 
int st[MAX_N], ed[MAX_N]; 
bool vis[MAX_N]; 
void dfs(int x) {
	vis[x] = 1, p[++top] = x; 
	for (int i = 1; i <= 16; i++) 
		if (dep[x] >= (1 << i)) { 
		    fa[x][i] = fa[fa[x][i - 1]][i - 1]; 
	        mx[x][i] = max(mx[x][i - 1], mx[fa[x][i - 1]][i - 1]); 
		}
		else break; 
	
	for (int i = fir[x]; ~i; i = e[i].next) { 
		int v = e[i].to; 
		dep[v] = dep[x] + 1; 
		mx[v][0] = val[x]; 
		fa[v][0] = x; 
		dfs(v); 
	} 
	if (x > N) p[++top] = x; 
} 
void build() { 
	int ext = N; 
	sort(&a[1], &a[M + 1]); 
	for (int i = 1; i <= 2 * N; i++) pa[i] = i; 
	for (int i = 1; i <= M; i++) { 
		int x = getf(a[i].u), y = getf(a[i].v); 
		if (x != y) { 
			ext++; 
			pa[x] = pa[y] = ext; 
			val[ext] = a[i].w;
			Add_Edge(ext, y); 
			Add_Edge(ext, x); 
			if (ext == 2 * N - 1) break; 
		} 
	} 
	for (int i = 1; i <= N; i++) if (!vis[i]) dfs(getf(i)); 
	for (int i = 1; i <= top; i++) { 
		int x = p[i];
		if (x <= N) insert(rt[i], rt[i - 1], 1, N, h[x]); 
		else {
			rt[i] = rt[i - 1]; 
			if (st[x] == 0) st[x] = i;
			else ed[x] = i; 
		} 
	} 
} 
int find(int x, int v) { 
	for (int i = 17; i >= 0; i--) 
		if (dep[x] >= (1 << i) && mx[x][i] <= v) x = fa[x][i]; 
	return x; 
}
int X[MAX_N]; 
int main () { 
	clearGraph(); 
	N = gi(), M = gi(), Q = gi();
	for (int i = 1; i <= N; i++) X[i] = h[i] = gi(); 
	for (int i = 1; i <= M; i++) {
		int u = gi(), v = gi(), w = gi(); 
		a[i] = (Edge){u, v, w}; 
	} 
	sort(&X[1], &X[N + 1]); 
	for (int i = 1; i <= N; i++) h[i] = lower_bound(&X[1], &X[N + 1], h[i]) - X; 
	build(); int ans = 0; 
	while (Q--) {
		int v = gi(), x = gi(), k = gi();
		if (ans != -1) v ^= ans, x ^= ans, k ^= ans; 
		x = find(v, x); 
		int l = st[x], r = ed[x]; 
		if (t[rt[r]].v - t[rt[l - 1]].v < k) ans = -1; 
		else ans = X[query(rt[l], rt[r], 1, N, t[rt[r]].v - t[rt[l - 1]].v - k + 1)]; 
		printf("%d
", ans); 
	} 
	return 0; 
} 
原文地址:https://www.cnblogs.com/heyujun/p/10334460.html