LG4197 Peaks

题意

题目描述

在Bytemountains有N座山峰,每座山峰有他的高度 h i h_i 。有些山峰之间有双向道路相连,共 M M 条路径,每条路径有一个困难值,这个值越大表示越难走,现在有 Q Q 组询问,每组询问询问从点 v v 开始只经过困难值小于等于 x x 的路径所能到达的山峰中第 k k 高的山峰,如果无解输出 1 -1

输入输出格式

输入格式:

第一行三个数 N N M M Q Q 。 第二行 N N 个数,第 i i 个数为 h i h_i 接下来 M M 行,每行 3 3 个数 a , b , c a,b,c ,表示从 a a b b 有一条困难值为 c c 的双向路径。 接下来 Q Q 行,每行三个数 v , x , k v,x,k ,表示一组询问。

输出格式:

对于每组询问,输出一个整数表示答案。

输入输出样例

输入样例#1: 复制
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
输出样例#1: 复制
6
1
-1
8

说明

数据范围

N 1 0 5 , 0 M , Q 5 × 1 0 5 , h i , c , x 1 0 9 N \le 10^5, 0 \le M,Q \le 5\times 10^5,h_i,c,x \le 10^9

分析

参照自为风月马前卒的题解。

首先由于给出的限制条件是<=x,因此我们在最小生成树上走一定是最优的。

考虑把Kruskal重构树建出来,重构树上每个新的节点代表的是边权,同时用倍增数组维护出向上跳2^i步后能走到的最大值

这样,该节点的整个子树内的节点都是可以走到的。

用dfs序+主席树维护出每个节点内H的值,直接查第K大即可

需要注意的是,对于不在原树内的节点,H要设的非常小,或者不插入,以免对答案产生影响

同时H需要离散化

时间复杂度\(O(n \log n)\)

代码

拒绝思考MLE的问题。

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
    rg T data=0,w=1;
    rg char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-') w=-1;
        ch=getchar();
    }
    while(isdigit(ch))
        data=data*10+ch-'0',ch=getchar();
    return data*w;
}
template<class T>il T read(rg T&x){
    return x=read<T>();
}
typedef long long ll;
using namespace std;

co int MAXN=5e5+1;
int N,M,Q,H[MAXN],date[MAXN],tot,num;
struct Edge{
    int u,v,w;
    bool operator<(co Edge&rhs)co {return w<rhs.w;}
}E[MAXN];
int fa[MAXN],fd[MAXN][22],dis[MAXN][22];
int find(int x) {return fa[x]==x?x:fa[x]=find(fa[x]);}
vector<int> v[MAXN];
//void Build(){
//  for(int i=1;i<N*2;++i) fa[i]=i;
//  sort(E+1,E+num+1);
//  for(int i=1;i<=num;++i){
//      int x=find(E[i].u),y=find(E[i].v);
//      if(x==y) continue;
//      ++tot,fa[x]=tot,fa[y]=tot;
//      v[x].push_back(tot),v[y].push_back(tot);
//      v[tot].push_back(x),v[tot].push_back(y);
//      dis[x][0]=E[i].w,dis[y][0]=E[i].w;
//      fd[x][0]=tot,fd[y][0]=tot;
//      if(tot==2*N-1) break;
//  }
//}
//int ls[MAXN*30],rs[MAXN*30],Tsiz[MAXN*30],root[MAXN],cnt,siz[MAXN],dfn[MAXN],tra[MAXN];
//void dfs(int x,int fa){
//  dfn[x]=++tot,tra[dfn[x]]=x,siz[x]=1;
//  for(int i=0;i<v[x].size();++i){
//      int to=v[x][i];
//      if(to==fa) continue;
//      dfs(to,x);
//      siz[x]+=siz[to];
//  }
//}
//void Insert(int&k,int p,int val,int l,int r){
//  if(val==-1) return void(k=p);
//  k=++cnt,ls[k]=ls[p],rs[k]=rs[p],Tsiz[k]=Tsiz[p]+1;
//  if(l==r) return;
//  int mid=l+r>>1;
//  if(val<=mid) Insert(ls[k],ls[p],val,l,mid);
//  else Insert(rs[k],rs[p],val,mid+1,r);
//}
//void MakeTree(){
//  cnt=0;
//  for(int i=1;i<=tot;++i)
//      Insert(root[i],root[i-1],H[tra[i]],1,N);
//}
//void Jump(){
//  for(int j=1;j<=21;++j)
//      for(int i=1;i<=tot;++i){
//          fd[i][j]=fd[fd[i][j-1]][j-1];
//          dis[i][j]=max(dis[fd[i][j-1]][j-1],dis[i][j-1]);
//      }
//}
//int Get(int x,int val){
//  for(int i=21;i>=0;--i)
//      if(dis[x][i]<=val&&fd[x][i]!=0)
//          x=fd[x][i];
//  return x;
//}
//int Query(int lt,int rt,int k,int l,int r){
//  int used=Tsiz[rs[rt]]-Tsiz[rs[lt]];
//  if(l==r){
//      if(Tsiz[rt]-Tsiz[lt]<k) return -1;
//      return l;
//  }
//  int mid=l+r>>1;
//  if(k<=used) return Query(rs[lt],rs[rt],k,mid+1,r);
//  else return Query(ls[lt],ls[rt],k-used,l,mid);
//}
void Build() {
    for(int i = 1; i <= (N << 1); i++) fa[i] = i;
    sort(E + 1, E + num + 1);
    for(int i = 1; i <= num; i++) {
        int x = E[i].u, y = E[i].v, w = E[i].w;
        int fx = find(x), fy = find(y);
        if(fx == fy) continue;
        tot++;
        fa[fx] = tot; fa[fy] = tot;
        v[fx].push_back(tot); v[fy].push_back(tot);
        v[tot].push_back(fx); v[tot].push_back(fy);
        dis[fx][0] = w; dis[fy][0] = w;
        fd[fx][0] = tot; fd[fy][0] = tot;
        if(tot == 2 * N - 1) break;
    }
}
int ls[MAXN * 30], rs[MAXN * 30], Tsiz[MAXN * 30], root[MAXN], cnt, siz[MAXN], dfn[MAXN], tra[MAXN];
void dfs(int x, int fa) {
    dfn[x] = ++cnt; tra[dfn[x]] = x; siz[x] = 1;
    for(int i = 0; i < v[x].size(); i++) {
        int to = v[x][i];
        if(to == fa) continue;
        dfs(to, x);
        siz[x] += siz[to];
    }
}
void update(int k) {
    Tsiz[k] = Tsiz[ls[k]] + Tsiz[rs[k]];
}
void Insert(int &k, int p, int val, int l, int r) {
    k = ++cnt;
    ls[k] = ls[p]; rs[k] = rs[p]; Tsiz[k] = Tsiz[p];
    if(val == -1) return ;
    Tsiz[k]++;
    if(l == r) return ;
    int mid = l + r >> 1;
    if(val <= mid) Insert(ls[k], ls[p], val, l, mid);
    else Insert(rs[k], rs[p], val, mid + 1, r);
    update(k);
}
void MakeTree() {
    cnt = 0;
    for(int i = 1; i <= tot; i++) 
        Insert(root[i], root[i - 1], H[tra[i]], 1, N);
}
void Jump() {
    for(int j = 1; j <= 21; j++) {
        for(int i = 1; i <= tot; i++) {
            fd[i][j] = fd[fd[i][j - 1]][j - 1];
            dis[i][j] = max(dis[fd[i][j - 1]][j - 1], dis[i][j - 1]);
        }
    }
}
int Get(int x, int val) {
    for(int i = 21; i >= 0; i--) 
        if(dis[x][i] <= val && fd[x][i] != 0) 
            x = fd[x][i];
    return x;
}
int Query(int lt, int rt, int k, int l, int r) {
    int used = Tsiz[rs[rt]] - Tsiz[rs[lt]];
    if(l == r) {
        if(Tsiz[rt] - Tsiz[lt] < k) return -1;
        else return l;
    } 
    int mid = l + r >> 1;
    if(k <= used) return Query(rs[lt], rs[rt], k, mid + 1, r);
    else return Query(ls[lt], ls[rt], k - used, l, mid);
}
int main(){
//  freopen(".in","r",stdin),freopen(".out","w",stdout);
    tot=read(N),read(M),read(Q);
    memset(H,-1,sizeof H);
    for(int i=1;i<=N;++i) date[i]=read(H[i]);
    sort(date+1,date+N+1);
    int tmp=unique(date+1,date+N+1)-date-1;
    for(int i=1;i<=N;++i) H[i]=lower_bound(date+1,date+tmp+1,H[i])-date;
    for(int i=1;i<=M;++i) E[++num]=(Edge){read<int>(),read<int>(),read<int>()};
    Build();
    dfs(tot,0);
    MakeTree();
    Jump();
    while(Q--){
        int v,x,k;
        read(v),read(x),read(k);
        int top=Get(v,x);
        int l=dfn[top],r=dfn[top]+siz[top]-1;
        int ans=Query(root[l],root[r],k,1,N);
        if(ans==-1) printf("%d\n",-1);
        else printf("%d\n",date[ans]);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/autoint/p/10547849.html
今日推荐