[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; }