下面称 Kruscal
建树的时候的产生的点的权值为 “权值”,题目中给的点权称作 “贡献”。
- 先是对于原图跑最小生成树的同时建立
Kruscal
重构树 - 随后 dfs 遍历整棵树,维护好倍增数组以及给叶子节点(原图节点)编号,并且处理出每个非叶子节点 uu 为根的子树中包含的叶子节点的编号 最大 / 最小值。
- 按照编号的顺序将叶子节点的 "贡献" 插入主席树中。
- 查询的时候就倍增找到询问的点 uu 在树中最远的一个满足权值 \leq x≤x 的节点 pp(因为深度越浅,权值越大),它为根的子树里面任意一个点跟 uu 的
LCA
的权值一定会 \leq p≤p 的权值。 - 求 pp 为根的子树中包含的叶子节点的 “贡献” 第 kk 大,因为编号连续,可以通过主席树区间查询。
时间复杂度:O(m \log n + n \log n)O(mlogn+nlogn),空间复杂度:O(n \log n)O(nlogn)
#include <bits/stdc++.h>
using namespace std;
inline int read() {
int x = 0, flag = 1;
char ch = getchar();
for( ; ch > '9' || ch < '0' ; ch = getchar()) if(ch == '-') flag = -1;
for( ; ch >= '0' && ch <= '9' ; ch = getchar()) x = (x << 3) + (x << 1) + ch - '0';
return x * flag;
}
const int MAXN = 2e5 + 50, MAXM = 5e5 + 50;
int n, m, f[MAXM + MAXN], tot, rt, start[MAXN], q, V[MAXN];
int fa[MAXN][20], L[MAXN], dfn_id[MAXN], R[MAXN], dep[MAXN], A[MAXN], now = 0;
int head, tail, Rt[MAXN], cnt = 0;
vector <int> Son[MAXN];
struct Edge {
int from, to, w;
} e[MAXM << 1];
int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
bool cmp(Edge a, Edge b) { return a.w < b.w; }
struct SegmentTree {
int ls, rs, Sum;
} T[MAXN * 16];
inline void DFS(int x, int from) {
fa[x][0] = from, dep[x] = dep[from] + 1;
L[x] = 1e9 + 7, R[x] = 0;
for(int i = 1 ; i <= log2(dep[x]) ; i ++)
fa[x][i] = fa[fa[x][i - 1]][i - 1];
if(!Son[x].size()) L[x] = R[x] = ++ now, dfn_id[now] = x;
for(int i = 0 ; i < Son[x].size(); i ++) {
int to = Son[x][i];
DFS(to, x);
L[x] = min(L[to], L[x]);
R[x] = max(R[to], R[x]);
}
return ;
}
inline int insert(int x, int l, int r, int pos) {
int cur = ++ cnt, mid = (l + r) >> 1;
T[cur] = T[x], T[cur].Sum ++;
if(l == r) return cur;
if(pos <= mid) T[cur].ls = insert(T[x].ls, l, mid, pos);
else T[cur].rs = insert(T[x].rs, mid + 1, r, pos);
return cur;
}
inline int Getfa(int x, int s) {
for(int i = log2(dep[x]) ; i >= 0 ; i --)
if(fa[x][i] != 0 && V[fa[x][i]] <= s) x = fa[x][i];
return x;
}
inline int GetAns(int u, int v, int l, int r, int k) {
int S = T[T[v].rs].Sum - T[T[u].rs].Sum, mid = (l + r) >> 1;
if(l == r) return l;
if(S >= k) return GetAns(T[u].rs, T[v].rs, mid + 1, r, k);
else return GetAns(T[u].ls, T[v].ls, l, mid, k - S);
}
signed main() {
//freopen("out","w",stdout);
n = read(), m = read(), q = read(), rt = n;
for(int i = 1 ; i <= n ; i ++) A[i] = read();
for(int i = 1 ; i <= m ; i ++) {
int u = read(), v = read(), w = read();
e[i] = (Edge) { u, v, w };
}
for(int i = 1 ; i <= n + m ; i ++) f[i] = i;
sort(e + 1, e + 1 + m, cmp);
for(int i = 1 ; i <= m ; i ++) {
int u = find(e[i].from), v = find(e[i].to);
if(u != v) {
rt ++, f[u] = f[v] = f[rt] = rt;
V[rt] = e[i].w;
Son[rt].push_back(u), Son[rt].push_back(v);
}
} DFS(rt, 0);
int Ans = 0;
for(int i = 1 ; i <= n ; i ++)
Rt[i] = insert(Rt[i - 1], 1, 1e9, A[dfn_id[i]]);
for(int i = 1 ; i <= q ; i ++) {
int u = (read() ^ Ans) % n + 1, x = read() ^ Ans, k = (read() ^ Ans) % n + 1;
u = Getfa(u, x);
if(R[u] - L[u] + 1 < k) Ans = 0, printf("-1\n");
else Ans = GetAns(Rt[L[u] - 1], Rt[R[u]], 1, 1e9, k), printf("%d\n", Ans);
}
return 0;
}