题目大意
有 n n n座山峰,每座山峰有他的高度 h [ i ] h[i] h[i]。有些山峰之间有双向道路相连,共m条路径,每条路径有一个困难值,这个值越大表示越难走。现在有 q q q组询问,每组询问询问从点 v v v开始只经过困难值小于等于 x x x的路径所能到达的山峰中第 k k k高的山峰,如果无解输出 − 1 −1 −1。
分析
- 对题目进行分析,看到"从点 v v v开始只经过困难值小于等于 x x x的路径"这句话时想到了最近一直在练的 K r u s k a l Kruskal Kruskal重构树,还有由于每次询问的是山峰中第 k k k高的山峰,所以不难想到运用主席树。
- 首先当然是先做一遍普通的重构树,然后跑一边 d f s dfs dfs。重构树中每一个非叶子节点对应的一定是一段连续的区间,所以开一个 r a n g e [ x ] [ 0 / 1 ] range[x][0/1] range[x][0/1]数组,表示 x x x节点的所维护的最左的叶子节点和最右的叶子节点,那么我们就可以比较清晰地做主席树了。在做 d f s dfs dfs时每跑到一个叶子节点就加到主席树中,对于每一组询问,先用倍增求出你所能到达的深度最小的点,然后用该节点的 r a n g e [ x ] [ 0 ] range[x][0] range[x][0]和 r a n g e [ x ] [ 1 ] range[x][1] range[x][1]做为两个历史版本做主席树的查询操作即可。
Code
#pragma GCC optimize(3)
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 2e5 + 10;
const int M = 5e5 + 10;
struct Node{
int from,to,val;
} g[M];
struct Edge{
int to,next;
} f[M << 1];
int n,m,q,fa[N],h[N][25],v[N],cnt,tot,head[N],rt[N << 5],ls[N << 5],rs[N << 5],a[N],b[N],sz,num,range[N][2],sum[N << 5];
int read()
{
int x = 0,w = 1;
char ch = getchar();
while (ch < '0' || ch > '9') {if (ch == '-') w = -1; ch = getchar();}
while (ch >= '0' && ch <= '9') {x = x * 10 + ch - '0'; ch = getchar();}
return x * w;
}
bool cmp(Node a,Node b) {return a.val < b.val;}
int find(int a) {return a == fa[a] ? a : fa[a] = find(fa[a]);}
void add(int u,int v)
{
f[++ cnt].to = v;
f[cnt].next = head[u];
head[u] = cnt;
}
void kruskal()
{
for (int i = 1; i <= 2 * n; i ++) fa[i] = i;
sort(g + 1,g + 1 + m,cmp);
tot = n;
for (int i = 1; i <= n; i ++)
{
int x = find(g[i].from),y = find(g[i].to);
if (x == y) continue;
fa[x] = fa[y] = ++ tot,v[tot] = g[i].val;
add(tot,x),add(tot,y);
h[x][0] = h[y][0] = tot;
}
}
void build(int &x,int l,int r)
{
x = ++ cnt;
if (l == r) return;
int mid = l + r >> 1;
build(ls[x],l,mid),build(rs[x],mid + 1,r);
}
void modify(int pre,int &rt,int l,int r,int k)
{
rt = ++ cnt;
sum[rt] = sum[pre] + 1;
if (l == r) return;
int mid = l + r >> 1;
if (k <= mid) rs[rt] = rs[pre],modify(ls[pre],ls[rt],l,mid,k); else ls[rt] = ls[pre],modify(rs[pre],rs[rt],mid + 1,r,k);
}
int query(int x,int y,int l,int r,int k)
{
if (l == r) return l;
int mid = l + r >> 1,q = sum[rs[y]] - sum[rs[x]];
if (k <= q) return query(rs[x],rs[y],mid + 1,r,k); else return query(ls[x],ls[y],l,mid,k - q);
}
void dfs(int u)
{
for (int i = 1; i <= 20; i ++) h[u][i] = h[h[u][i - 1]][i - 1];
range[u][0] = num;
if (!head[u])
{
int x = lower_bound(b + 1,b + 1 + sz,a[u]) - b;
range[u][0] = ++ num;
modify(rt[num - 1],rt[num],1,sz,x);
return;
}
for (int i = head[u]; i; i = f[i].next)
dfs(f[i].to);
range[u][1] = num;
}
int main()
{
n = read(),m = read(),q = read();
for (int i = 1; i <= n; i ++) a[i] = b[i] = read();
sort(b + 1,b + 1 + n);
sz = unique(b + 1,b + 1 + n) - b - 1;
for (int i = 1; i <= m; i ++)
g[i].from = read(),g[i].to = read(),g[i].val = read();
kruskal();
cnt = 0;
build(rt[0],1,sz);
dfs(tot);
while (q --)
{
int x = read(),y = read(),z = read();
for (int i = 20; i >= 0; i --)
if (h[x][i] && v[h[x][i]] <= y) x = h[x][i];
if (range[x][1] - range[x][0] < z) printf("%d\n",-1);
else printf("%d\n",b[query(rt[range[x][0]],rt[range[x][1]],1,sz,z)]);
}
return 0;
}