【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=3551
【题解】
这一题要求强制在线,所以要维护历史版本的信息。
考虑kruskal求最小生成树,显然询问是对在做最小生成树的过程中对一个联通块进行查询,所以可以想办法把这个过程可持久化。
对于每条在最小生成树上的边(u,v),将u,v跳到所在的最高父亲,然后不是直接合并,而是新建一个点,做一次可持久化线段树合并,把(u,v)的父亲设为这个点。对于每个询问,从它开始向上跳,显然向上跳的困难度单调增,所以跳到能跳的最高的那个点,在所对应的线段树查询一次。
时间复杂度
O(N∗logN)
O
(
N
∗
l
o
g
N
)
【代码】
/* - - - - - - - - - - - - - - -
User : VanishD
problem : [bzoj3551]
Points : segment tree
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 200010
# define M 500010
# define K 18
using namespace std;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
int L, R = 1e9;
struct Edge{
int u, v, w, id;
}e[M], h[N];
struct Tree{
int pl, pr, num;
}T[8000000];
int f[N], place, n, m, q, rt[N], fa[N][K + 1], number[N], vote[N];
bool cmp(Edge x, Edge y){
return x.w < y.w;
}
int dad(int x){
if (f[x] == x) return f[x];
return f[x] = dad(f[x]);
}
int extend(int p, int data, int l, int r){
if (!p) p = ++place;
T[p].num++;
if (l != r){
int mid = (l + r) / 2;
if (mid >= data) T[p].pl = extend(T[p].pl, data, l, mid);
else T[p].pr = extend(T[p].pr, data, mid + 1, r);
}
return p;
}
int merge(int p1, int p2, int l, int r){
if (p1 == 0) return p2;
if (p2 == 0) return p1;
int p = ++place;
T[p].num = T[p1].num + T[p2].num;
if (l != r){
int mid = (l + r) / 2;
T[p].pl = merge(T[p1].pl, T[p2].pl, l, mid);
T[p].pr = merge(T[p1].pr, T[p2].pr, mid + 1, r);
}
return p;
}
int query(int p, int data, int l, int r){
if (l == r) return l;
int mid = (l + r) / 2;
if (T[T[p].pr].num >= data)
return query(T[p].pr, data, mid + 1, r);
else return query(T[p].pl, data - T[T[p].pr].num, l, mid);
}
void pre(int n){
for (int i = 1, j = 1; j * 2 <= n; i++, j *= 2)
for (int k = 1; k <= n; k++)
fa[k][i] = fa[fa[k][i - 1]][i - 1];
}
int main(){
// freopen("bzoj3551.in", "r", stdin);
// freopen("bzoj3551.out", "w", stdout);
n = read(), m = read(), q = read();
for (int i = 1; i <= n; i++)
h[i].u = i, h[i].w = read();
for (int i = 1; i <= 2 * n; i++) f[i] = i;
sort(h + 1, h + n + 1, cmp);
for (int i = 1; i <= n; i++)
rt[h[i].u] = extend(0, h[i].w, L, R);
for (int i = 1; i <= m; i++)
e[i].u = read(), e[i].v = read(), e[i].w = read();
sort(e + 1, e + m + 1, cmp);
for (int i = 1, tmp = n; i <= m; i++){
int u = dad(e[i].u), v = dad(e[i].v);
if (u == v) continue;
rt[++tmp] = merge(rt[u], rt[v], L, R);
fa[u][0] = tmp, fa[v][0] = tmp;
vote[tmp] = e[i].w;
f[u] = tmp, f[v] = tmp;
}
pre(n * 2);
int lastans = 0;
for (int i = 1; i <= q; i++){
int v = read() ^ lastans,
u = read() ^ lastans,
k = read() ^ lastans;
for (int i = K; i >= 0; i--)
if (fa[v][i] != 0 && vote[fa[v][i]] <= u)
v = fa[v][i];
if (T[rt[v]].num < k){
printf("%d\n", -1);
lastans = 0;
}
else {
lastans = query(rt[v], k, L, R);
printf("%d\n", lastans);
}
}
return 0;
}