[BZOJ3545]Peaks

题目大意:
有N座山峰,每座山峰有他的高度\(h_i\)。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
解题思路:
本题可以离线。
所以我们先对询问排序,然后按照Kruskal的思路,用并查集维护连通块,对每个连通块内建权值线段树。
合并两个连通块时,做线段树合并即可。
然后对于询问,在当前块内查询即可。
时间复杂度\(O(n\log n)\)。

C++ Code:

#include<bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
using namespace std;
using namespace __gnu_pbds;
const int N=(1<<17)-1;
struct node{
    int ls,rs,s;
}d[N<<5];
struct asks{
    int u,x,k,id;
    inline bool operator<(const asks&rhs)const{return x<rhs.x;}
}q[N<<2];
struct edge{
    int u,v,dis;
    inline bool operator<(const edge&rhs)const{return dis<rhs.dis;}
}e[N<<2];
int n,m,Q,cnt=0,rt[N]={0},h[N],fa[N],ans[N<<2];
int kk,aans;
tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>s;
template<typename T>
inline void read(T&d){
    int c=getchar();d=0;
    for(;!isdigit(c);c=getchar());
    for(;isdigit(c);c=getchar())
    d=(d<<3)+(d<<1)+(c^'0');
}
void ins(int&o,int l,int r,int h){
    if(!o)o=++cnt;
    ++d[o].s;
    if(l==r)return;
    int mid=l+r>>1;
    if(h<=mid)ins(d[o].ls,l,mid,h);else
    ins(d[o].rs,mid+1,r,h);
}
inline int find(int x){return x==fa[x]?x:fa[x]=find(fa[x]);}
int node_merge(int ls,int rs){
    if(!ls||!rs)return ls|rs;
    if(!d[ls].ls&&!d[ls].rs){
        d[ls].s+=d[rs].s;
        return ls;
    }
    d[ls].ls=node_merge(d[ls].ls,d[rs].ls);
    d[ls].rs=node_merge(d[ls].rs,d[rs].rs);
    d[ls].s=d[d[ls].ls].s+d[d[ls].rs].s;
    return ls;
}
void edge_merge(int now){
    int x=find(e[now].u),y=find(e[now].v);
    if(x!=y){
        fa[y]=x;
        rt[x]=node_merge(rt[x],rt[y]);
    }
}
void query(int&o,int l,int r){
    if(l==r)aans=l;else{
        int mid=l+r>>1;
        if(kk<=d[d[o].rs].s)query(d[o].rs,mid+1,r);else{
            kk-=d[d[o].rs].s;
            query(d[o].ls,l,mid);
        }
    }
}
int main(){
    memset(d,0,sizeof d);
    read(n),read(m),read(Q);
    for(int i=1;i<=n;++i){
        read(h[i]);
        s.insert(h[i]);
    }
    for(int i=1;i<=n;++i)h[i]=s.order_of_key(h[i]);
    for(int i=1;i<=n;++i)ins(rt[i],0,N,h[i]);
    for(int i=1;i<=m;++i)read(e[i].u),read(e[i].v),read(e[i].dis);
    sort(e+1,e+m+1);
    for(int i=1;i<=Q;++i)read(q[i].u),read(q[i].x),read(q[i].k),q[i].id=i;
    sort(q+1,q+Q+1);
    e[m+1].dis=0x7fffffff;
    for(int i=1;i<=n;++i)fa[i]=i;
    for(int pe=1,pq=1;pq<=Q;){
        if(e[pe].dis<=q[pq].x)edge_merge(pe++);else{
            int u=find(q[pq].u);
            if(d[rt[u]].s<q[pq].k){
                ans[q[pq++].id]=-1;
                continue;
            }
            aans=0;
            kk=q[pq].k;
            query(rt[u],0,N);
            ans[q[pq++].id]=*s.find_by_order(aans);
        }
    }
    for(int i=1;i<=Q;++i)printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2018-07-23 13:15  Mrsrz  阅读(183)  评论(0编辑  收藏  举报