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;
}