Bzoj3551: [ONTAK2010]Peaks加强版

题面

题目传送门

\(Bytemountains\)\(N\)座山峰,每座山峰有他的高度\(h_i\)
有些山峰之间有双向道路相连,共\(M\)条路径,每条路径有一个困难值,这个值越大表示越难走
现在有\(Q\)组询问
每组询问询问从点\(v\)开始只经过困难值小于等于\(x\)的路径所能到达的山峰中第\(k\)高的山峰,如果无解输出\(-1\)
\(N<=10^5, M,Q<=5*10^5\)\(h_i,c,x<=10^9\)

Sol

\(Kruskal\)重构树+倍增+主席树
做一遍\(Kruskal\)最小生成树
询问时\(v\)往上跳到最后一个小于等于\(x\)的值,然后求这个点的子树的叶节点的第\(k\)大,可以证明这个子树外的无论如何都走不到

# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(2e5 + 5);
const int __(5e5 + 5);

IL int Input(){
    RG int x = 0, z = 1; RG char c = getchar();
    for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
    for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
    return x * z;
}

int n, m, q, L[_], R[_], w[_], h[_], fa[_], anc[20][_], id[_];
int o[_], len;
struct Link{
	int u, v, w;

	IL bool operator <(RG Link B) const{
		return w < B.w;
	}
} lnk[__];
int first[_], cnt, num, idx;
struct Edge{
	int to, next;
} edge[_];

IL void Add(RG int u, RG int v){
	edge[cnt] = (Edge){v, first[u]}, first[u] = cnt++;
}

IL int Find(RG int x){
	return x == fa[x] ? x : fa[x] = Find(fa[x]);
}

IL void Dfs(RG int u){
	L[u] = n, R[u] = 1;
	if(u <= n) L[u] = R[u] = ++idx, id[idx] = u;
	for(RG int e = first[u]; e != -1; e = edge[e].next){
		RG int v = edge[e].to;
		anc[0][v] = u, Dfs(v);
		L[u] = min(L[u], L[v]), R[u] = max(R[u], R[v]);
	}
}

int rt[_], tot;
struct HJT{
	int ls, rs, sz;
} T[_ * 20];

IL void Modify(RG int &x, RG int l, RG int r, RG int p){
	T[++tot] = T[x], T[x = tot].sz++;
	if(l == r) return;
	RG int mid = (l + r) >> 1;
	if(p <= mid) Modify(T[x].ls, l, mid, p);
	else Modify(T[x].rs, mid + 1, r, p);
}

IL int Query(RG int A, RG int B, RG int l, RG int r, RG int k){
	if(l == r) return o[l];
	RG int mid = (l + r) >> 1, size = T[T[B].rs].sz - T[T[A].rs].sz;
	if(k <= size) return Query(T[A].rs, T[B].rs, mid + 1, r, k);
	return Query(T[A].ls, T[B].ls, l, mid, k - size);
}

IL int Calc(RG int u, RG int x, RG int k){
	RG int p = u;
	for(RG int j = 18; ~j; --j) if(anc[j][p] && w[anc[j][p]] <= x) p = anc[j][p];
	if(R[p] - L[p] + 1 < k) return -1;
	return Query(rt[L[p] - 1], rt[R[p]], 1, len, k);
}

int main(RG int argc, RG char* argv[]){
	num = n = Input(), m = Input(), q = Input();
	for(RG int i = 1; i <= n; ++i) fa[i] = i, o[i] = h[i] = Input();
	sort(o + 1, o + n + 1), len = unique(o + 1, o + n + 1) - o - 1;
	for(RG int i = 1; i <= n; ++i) h[i] = lower_bound(o + 1, o + len + 1, h[i]) - o;
	for(RG int i = 1; i <= m; ++i) lnk[i].u = Input(), lnk[i].v = Input(), lnk[i].w = Input();
	sort(lnk + 1, lnk + m + 1), Fill(first, -1);
	for(RG int i = 1; i <= m; ++i){
		RG int fx = Find(lnk[i].u), fy = Find(lnk[i].v);
		if(fx == fy) continue;
		w[++num] = lnk[i].w, fa[fx] = fa[fy] = fa[num] = num;
		Add(num, fx), Add(num, fy);
	}
	for(RG int i = 1; i <= num; ++i) if(fa[i] == i) Dfs(i);
	for(RG int j = 1; j <= 18; ++j)
		for(RG int i = 1; i <= num; ++i)
			anc[j][i] = anc[j - 1][anc[j - 1][i]];
	for(RG int i = 1; i <= n; ++i) rt[i] = rt[i - 1], Modify(rt[i], 1, len, h[id[i]]);
	for(RG int i = 1, ans = 0; i <= q; ++i){
		RG int v = Input(), x = Input(), k = Input();
		if(ans != -1) v ^= ans, x ^= ans, k ^= ans;
		printf("%d\n", ans = Calc(v, x, k));
	}
    return 0;
}

posted @ 2018-03-13 17:44  Cyhlnj  阅读(110)  评论(0编辑  收藏  举报