题目描述
在Bytemountains有N座山峰,每座山峰有它的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
输入格式
第一行三个数N,M,Q。
第二行N个数,第i个数为h_i。
接下来M行,每行3个数a b c,表示从a到b有一条困难值为c的双向路径。
接下来Q行,每行三个数v x k,表示一组询问。
输出格式
对于每组询问,输出一个整数表示所求山峰的高度。
数据范围
N<=105, M,Q<=5*105,hi,c,x<=109。
分析
由于题目没有要求要在线,于是考虑离线。读入所有的边和询问,将边和询问分别按照 和 从小到大排序。然后对每个点开 棵 ,对于每个询问,将所有 的边的两顶点的 合并起来,然后在 所在的 中查询第 大。由于先排序了的,所以顺序处理每个询问,在上一个询问的基础上合并。
代码
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
const int N=100005,M=500005;
typedef long long LL;
struct Edge {
int x,y,w;
bool operator<(const Edge&e) const {
return w<e.w;
}
}e[M];
struct Query {
int v,x,k,id;
bool operator<(const Query&e) const {
return x<e.x;
}
}q[M];
int n,m,Q,sz[N];
int v[N],f[N],c[N][2],ans[M];
int fa[N],pt[N],st[N],top;
void Pushup(int x) {if (x) sz[x]=sz[c[x][0]]+sz[c[x][1]]+1;}
int Getf(int x) {return fa[x]==x?x:fa[x]=Getf(fa[x]);}//用并查集判断联通性
void Rotate(int x) {
int y=f[x],z=f[y];
int k=c[y][1]==x,kk=c[z][1]==y;
c[y][k]=c[x][k^1];
f[c[x][k^1]]=y;
c[x][k^1]=y;
f[y]=x;
if (z) c[z][kk]=x;
f[x]=z;
Pushup(y);
Pushup(x);
}
void Splay(int x) {
while (f[x]) {
int y=f[x],z=f[y];
if (z) {
if ((c[y][1]==x)^(c[z][1]==y)) Rotate(x);
else Rotate(y);
}
Rotate(x);
}
}
void Insert(int p,int q) {
while (1) {
sz[p]++;
int nxt=(v[q]<=v[p]?0:1);
if (!c[p][nxt]) {
c[p][nxt]=q;
f[q]=p;
c[q][0]=c[q][1]=0;
sz[q]=1;
Splay(q);
return;
}
p=c[p][nxt];
}
}//以上Splay基本操作
void Dfs(int x) {
if (!x) return;
Dfs(c[x][0]);
st[++top]=x;
Dfs(c[x][1]);
}
void Merge(int x,int y) {
int fx=Getf(x);
int fy=Getf(y);
if (fx==fy) return;
fa[fy]=fx;
Splay(x);
Splay(y);
if (sz[x]<sz[y]) swap(x,y);//启发式,将小的向大的合并
Dfs(y);//获得中序遍历序,据说可以减少时间复杂度
st[top+1]=x;
while (top) {
Insert(st[top+1],st[top]);//一个个插入
top--;
}
}
int Kth(int p,int k) {
Splay(p);
if (k>sz[p]) return -1;
k=sz[p]-k+1;
while (1) {
if (sz[c[p][0]]+1==k) return v[p];
if (sz[c[p][0]]>=k) p=c[p][0];
else {
k-=sz[c[p][0]]+1;
p=c[p][1];
}
}
}
int main() {
scanf("%d%d%d",&n,&m,&Q);
for (int i=1;i<=n;i++) scanf("%d",&v[i]),fa[i]=i,sz[i]=1;//读入并初始化
for (int i=1;i<=m;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w);
for (int i=1;i<=Q;i++) scanf("%d%d%d",&q[i].v,&q[i].x,&q[i].k),q[i].id=i;
sort(e+1,e+m+1);
sort(q+1,q+Q+1);
int ei,qi;
ei=qi=1;
while (qi<=Q) {
while (ei<=m&&e[ei].w<=q[qi].x) {
Merge(e[ei].x,e[ei].y);
ei++;
}
ans[q[qi].id]=Kth(q[qi].v,q[qi].k);
qi++;
}
for (int i=1;i<=Q;i++) printf("%d\n",ans[i]);
return 0;
}