1. 程式人生 > >BZOJ3545 Peaks 離線處理+線段樹合並

BZOJ3545 Peaks 離線處理+線段樹合並

names 線段 amp spa 有一個 一個 open ace nta

題意:

  在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 }
線段樹合並

BZOJ3545 Peaks 離線處理+線段樹合並