(color{#0066ff}{题目描述})
在Bytemountains有N座山峰,每座山峰有他的高度(h_i) 。有些山峰之间有双向道路相连,共(M)条路径,每条路径有一个困难值,这个值越大表示越难走,现在有(Q)组询问,每组询问询问从点(v)开始只经过困难值小于等于(x)的路径所能到达的山峰中第(k)高的山峰,如果无解输出(-1)。
(color{#0066ff}{输入格式})
第一行三个数(N,M,Q)。 第二行(N)个数,第i个数为(h_i) 接下来(M)行,每行(3)个数(a,b,c),表示从(a)到(b)有一条困难值为(c)的双向路径。 接下来(Q)行,每行三个数(v,x,k) 表示一组询问。
(color{#0066ff}{输出格式})
对于每组询问,输出一个整数表示答案。
(color{#0066ff}{输入样例})
10 11 4
1 2 3 4 5 6 7 8 9 10
1 4 4
2 5 3
9 8 2
7 8 10
7 1 4
6 7 1
6 4 8
2 1 5
10 8 10
3 4 7
3 4 6
1 5 2
1 5 6
1 5 8
8 9 2
(color{#0066ff}{输出样例})
6
1
-1
8
(color{#0066ff}{数据范围与提示})
(N leq 10^5, 0 leq M, Q leq 5 * 10^5, h_i, c, x leq 10^9)
(color{#0066ff}{题解})
Kruskal重构树
以困难程度为关键字建立大根堆
倍增找到最浅点
对于子树内的叶子,就是能到的所有点
找到这些点的第k大
考虑dfs序
只记录叶子节点的dfs序
同一子树内dfs序连续
用主席树维护就行了
#include<bits/stdc++.h>
#define LL long long
LL in() {
char ch; int x = 0, f = 1;
while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
return x * f;
}
const int maxn = 8e5 + 100;
struct tree {
protected:
struct node {
int num;
node *ch[2];
node(int num = 0): num(num) {
ch[0] = ch[1] = NULL;
}
void *operator new (size_t) {
static node *S = NULL, *T = NULL;
return (S == T) && (T = (S = new node[1024]) + 1024), S++;
}
};
node *root[maxn];
void ins(node *&o, node *ls, int l, int r, int val) {
o = new node();
*o = *ls;
o->num++;
if(l == r) return;
int mid = (l + r) >> 1;
if(val <= mid) ins(o->ch[0], ls->ch[0], l, mid, val);
else ins(o->ch[1], ls->ch[1], mid + 1, r, val);
}
int query(node *x, node *y, int l, int r, int k) {
if(l == r) return l;
int siz = y->ch[0]->num - x->ch[0]->num;
int mid = (l + r) >> 1;
if(k <= siz) return query(x->ch[0], y->ch[0], l, mid, k);
else return query(x->ch[1], y->ch[1], mid + 1, r, k - siz);
}
void init() {
root[0] = new node();
root[0]->ch[0] = root[0]->ch[1] = root[0];
}
public:
tree() { init(); }
void ins(int *s, int *t, int *m, int n, int len) {
for(int i = 1; i <= n; i++) ins(root[i], root[i - 1], 1, len, std::lower_bound(t + 1, t + len + 1, s[m[i]]) - t);
}
int query(int l, int r, int k, int len) { return query(root[l - 1], root[r], 1, len, k); }
};
int n, m, q;
struct E {
int x, y, z;
bool operator < (const E &b) const {
return z < b.z;
}
}e[maxn];
struct node {
int to;
node *nxt;
node(int to = 0, node *nxt = NULL): to(to), nxt(nxt) {}
void *operator new (size_t) {
static node *S = NULL, *T = NULL;
return (S == T) && (T = (S = new node[1024]) + 1024), S++;
}
};
node *head[maxn];
tree s;
int h[maxn], l[maxn], r[maxn], fa[maxn], hh[maxn], len = 1;
int findset(int x) { return x == fa[x]? fa[x] : fa[x] = findset(fa[x]); }
int f[maxn][26], dfn, redfn[maxn];
void add(int from, int to) {
head[from] = new node(to, head[from]);
}
void dfs(int x, int ff) {
f[x][0] = ff;
if(x <= n) redfn[++dfn] = x;
else l[x] = dfn + 1;
for(node *i = head[x]; i; i = i->nxt)
if(i->to != ff) dfs(i->to, x);
if(x > n) r[x] = dfn;
}
int query(int v, int x, int k) {
for(int i = 24; i >= 0; i--) if(f[v][i] && h[f[v][i]] <= x) v = f[v][i];
if(r[v] - l[v] + 1 < k) return -1;
return hh[s.query(l[v], r[v], r[v] - l[v] + 2 - k, len)];
}
int main() {
n = in(), m = in(), q = in();
for(int i = 1; i <= n; i++) hh[i] = h[i] = in(), fa[i] = i;
for(int i = 1; i <= m; i++) e[i].x = in(), e[i].y = in(), e[i].z = in();
std::sort(hh + 1, hh + n + 1);
std::sort(e + 1, e + m + 1);
for(int i = 2; i <= n; i++) if(hh[i] != hh[i - 1]) hh[++len] = hh[i];
int cnt = n, tot = 0;
for(int i = 1; i <= m; i++) {
int x = findset(e[i].x);
int y = findset(e[i].y);
if(x != y) {
fa[x] = fa[y] = ++cnt;
fa[cnt] = cnt;
h[cnt] = e[i].z;
add(cnt, x), add(cnt, y);
tot++;
}
if(tot == n - 1) break;
}
dfs(cnt, 0);
for(int j = 1; j <= 24; j++)
for(int i = 1; i <= cnt; i++)
f[i][j] = f[f[i][j - 1]][j - 1];
s.ins(h, hh, redfn, n, len);
int v, x, k;
while(q --> 0) {
v = in(), x = in(), k = in();
printf("%d
", query(v, x, k));
}
return 0;
}