BZOJ3545 Peaks 离线处理+线段树合并
题意:
在Bytemountains有N座山峰,每座山峰有他的高度h_i。有些山峰之间有双向道路相连,共M条路径,每条路径有一个困难值,这个值越大表示越难走,现在有Q组询问,每组询问询问从点v开始只经过困难值小于等于x的路径所能到达的山峰中第k高的山峰,如果无解输出-1。
分析:
我们把题目中的限制分离出来:
1. 困难值不超过x。
2. 能达到的第k高的山峰。
如果没有限制1,我们对每个连通块建线段树即可,如果没有限制2,我们我们可以选择按照kruskal的思想,按照困难值从小到大加便,离线处理询问。
现在两个限制都在,所以我们考虑使两种算法兼容,所以我们连边时如果两个端点分别属于不同的连通块,我们就合并两个连通块,需要处理的问题是并查集合并和线段树合并。同时离线处理询问即可。
这题还有一个加强版,是强制在线的版本,应该是一道kruskal重构树的练手题。
代码:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=100005; 4 struct que{int a,b,c,id,ok;}a[N*10]; 5 struct seg{int ls,rs,v;}t[N*50]; 6 int n,m,q,tot=0,nm1[N],nm2[N],fa[N],rt[N],ans[N*5]; 7 bool cmp(que a,que b){ 8 return a.c==b.c?a.ok<b.ok:a.c<b.c; 9 } int get(int x){ 10 return fa[x]==x?x:fa[x]=get(fa[x]); 11 } void update(int &x,int l,int r,int v){ 12 if(!x) x=++tot;t[x].v=1; 13 if(l==r) return ;int mid=l+r>>1; 14 if(v<=mid) update(t[x].ls,l,mid,v); 15 else update(t[x].rs,mid+1,r,v); 16 } int query(int x,int l,int r,int p){ 17 if(l==r) return l;int mid=l+r>>1; 18 if(p<=t[t[x].ls].v) 19 return query(t[x].ls,l,mid,p); 20 else return 21 query(t[x].rs,mid+1,r,p-t[t[x].ls].v); 22 } int merge(int x,int y){ 23 if(!x||!y) return x|y; 24 if(!t[x].ls&&!t[x].rs){ 25 t[x].v+=t[y].v;return x; 26 } t[x].ls=merge(t[x].ls,t[y].ls); 27 t[x].rs=merge(t[x].rs,t[y].rs); 28 t[x].v=t[t[x].ls].v+t[t[x].rs].v; 29 return x; 30 } int main(){ 31 scanf("%d%d%d",&n,&m,&q); 32 for(int i=1;i<=n;i++) 33 scanf("%d",&nm1[i]), 34 nm2[i]=nm1[i],fa[i]=i; 35 sort(nm2+1,nm2+n+1); 36 for(int i=1;i<=n;i++) 37 nm1[i]=lower_bound(nm2+1,nm2+1+n,nm1[i])-nm2; 38 for(int i=1,x,y,z;i<=m;i++) 39 scanf("%d%d%d",&x,&y,&z), 40 a[i]=(que){x,y,z,0,0}; 41 for(int i=m+1,x,y,z;i<=m+q;i++) 42 scanf("%d%d%d",&x,&y,&z), 43 a[i]=(que){x,z,y,i-m,1}; 44 sort(a+1,a+1+m+q,cmp); 45 for(int i=1;i<=n;i++) 46 update(rt[i],1,n,nm1[i]); 47 for(int i=1;i<=m+q;i++) 48 if(!a[i].ok){ 49 int x=get(a[i].a),y=get(a[i].b); 50 if(x!=y) fa[x]=y, 51 rt[y]=merge(rt[x],rt[y]); 52 } else{ 53 int x=get(a[i].a); 54 if(t[rt[x]].v<a[i].b) 55 ans[a[i].id]=-1; 56 else ans[a[i].id]= 57 nm2[query(rt[x],1,n,t[rt[x]].v-a[i].b+1)]; 58 } for(int i=1;i<=q;i++) 59 printf("%d\n",ans[i]);return 0; 60 }