#3551. [ONTAK2010]Peaks加强版

我们要求从一个点出发经过困难值小于等于 x x x的路径所能到达的山峰中第 k k k高的是什么。

考虑按照边权升序,建议 k r u s k a l kruskal kruskal重构树,然后倍增向上跳,找到困难值小于等于 x x x的深度最小的节点 u u u

那么我们只要在 u u u的子树中询问第 k k k大即可,所以可以用主席树来写,依照 d f s dfs dfs序,对每个节点建立一颗主席树,然后在主席树上查找第 k k k大即可。

#include <bits/stdc++.h>

using namespace std;

const int N = 5e5 + 10;

int head[N], to[N], nex[N], cnt = 1;

int n, m, q, nn, a[N], ff[N], value[N], h[N];

int fa[N][21], l[N], r[N], rk[N], tot;

int root[N], ls[N << 7], rs[N << 7], sum[N << 7], num;

struct Res {
  int u, v, w;

  bool operator < (const Res &t) const {
    return w < t.w;
  }
}edge[N];

void add(int x, int y) {
  to[cnt] = y;
  nex[cnt] = head[x];
  head[x] = cnt++;
}

void update(int &rt, int pre, int l, int r, int x, int v) {
  rt = ++num;
  ls[rt] = ls[pre], rs[rt] = rs[pre], sum[rt] = sum[pre] + v;
  if (l == r) {
    return ;
  }
  int mid = l + r >> 1;
  if (x <= mid) {
    update(ls[rt], ls[pre], l, mid, x, v);
  }
  else {
    update(rs[rt], rs[pre], mid + 1, r, x, v);
  }
}

int query(int L, int R, int l, int r, int k) {
  if (l == r) {
    return l;
  }
  int res = sum[ls[R]] - sum[ls[L]], mid = l + r >> 1;
  if (res >= k) {
    return query(ls[L], ls[R], l, mid, k);
  }
  else {
    return query(rs[L], rs[R], mid + 1, r, k - res);
  }
}

int find(int rt) {
  return rt == ff[rt] ? rt : ff[rt] = find(ff[rt]);
}

void dfs(int rt, int f) {
  fa[rt][0] = f, l[rt] = ++tot, rk[tot] = rt;
  for (int i = 1; i <= 20; i++) {
    fa[rt][i] = fa[fa[rt][i - 1]][i - 1];
  }
  for (int i = head[rt]; i; i = nex[i]) {
    if (to[i] == f) {
      continue;
    }
    dfs(to[i], rt);
  }
  r[rt] = tot;
}

void kruskal() {
  for (int i = 1; i < N; i++) {
    ff[i] = i;
  }
  sort(edge + 1, edge + 1 + m);
  for (int i = 1, cur = 1; i <= m && cur < n; i++) {
    int u = find(edge[i].u), v = find(edge[i].v);
    if (u != v) {
      cur++, nn++;
      ff[u] = nn, ff[v] = nn;
      value[nn] = edge[i].w;
      add(nn, u), add(nn, v);
      if (u <= n) {
        value[u] = edge[i].w;
      }
      if (v <= n) {
        value[v] = edge[i].w;
      }
    }
  }
  dfs(nn, 0);
}

int main() {
  // freopen("in.txt", "r", stdin);
  // freopen("out.txt", "w", stdout);
  // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
  scanf("%d %d %d", &n, &m, &q);
  for (int i = 1; i <= n; i++) {
    scanf("%d", &h[i]);
    a[i] = h[i];
  }
  nn = n;
  for (int i = 1; i <= m; i++) {
    scanf("%d %d %d", &edge[i].u, &edge[i].v, &edge[i].w);
  }
  kruskal();
  int maxn = n;
  sort(a + 1, a + 1 + maxn);
  maxn = unique(a + 1, a + 1 + maxn) - (a + 1);
  for (int i = 1; i <= n; i++) {
    h[i] = lower_bound(a + 1, a + 1 + maxn, h[i]) - a; 
  }
  for (int i = 1; i <= nn; i++) {
    root[i] = root[i - 1];
    if (rk[i] <= n) {
      update(root[i], root[i], 1, maxn, h[rk[i]], 1);
    }
  }
  for (int i = 1, u, x, k, last_ans = 0, res; i <= q; i++) {
    scanf("%d %d %d", &u, &x, &k);
    if (last_ans != -1) {
      u ^= last_ans, x ^= last_ans, k ^= last_ans;
    }
    for (int j = 20; j >= 0; j--) {
      if (fa[u][j] && value[fa[u][j]] <= x) {
        u = fa[u][j];
      }
    }
    res = sum[root[r[u]]] - sum[root[l[u] - 1]];
    last_ans = res < k ? -1 : a[query(root[l[u] - 1], root[r[u]], 1, maxn, res - k + 1)];
    printf("%d\n", last_ans);
  }
  return 0;
}