【BZOJ2733】【HNOI2012】永無鄉 - 線段樹合併

題意:

Description

永無鄉包含 n 座島,編號從 1 到 n,每座島都有本身的獨一無二的重要度,按照重要度可 以將這 n 座島排名,名次用 1 到 n 來表示。某些島之間由巨大的橋鏈接,經過橋能夠從一個島 到達另外一個島。若是從島 a 出發通過若干座(含 0 座)橋能夠到達島 b,則稱島 a 和島 b 是連 通的。如今有兩種操做:B x y 表示在島 x 與島 y 之間修建一座新橋。Q x k 表示詢問當前與島 x連通的全部島中第 k 重要的是哪座島,即全部與島 x 連通的島中重要度排名第 k 小的島是哪 座,請你輸出那個島的編號。 
node

對於 20%的數據 n≤1000,q≤1000
對於 100%的數據 n≤100000,m≤n,q≤300000 ios

Input

輸入文件第一行是用空格隔開的兩個正整數 n 和 m,分別 表示島的個數以及一開始存在的橋數。接下來的一行是用空格隔開的 n 個數,依次描述從島 1 到島 n 的重要度排名。隨後的 m 行每行是用空格隔開的兩個正整數 ai 和 bi,表示一開始就存 在一座鏈接島 ai 和島 bi 的橋。後面剩下的部分描述操做,該部分的第一行是一個正整數 q, 表示一共有 q 個操做,接下來的 q 行依次描述每一個操做,操做的格式如上所述,以大寫字母 Q 或B 開始,後面跟兩個不超過 n 的正整數,字母與數字以及兩個數字之間用空格隔開。spa

Output

對於每一個 Q x k 操做都要依次輸出一行,其中包含一個整數,表 示所詢問島嶼的編號。若是該島嶼不存在,則輸出-1。 code

題解:

咦爲何以前線段樹合併專題的時候我沒寫這題……blog

大水題套路題,權值線段樹維護每一個聯通塊,並查集維護加邊,每次合併聯通塊時線段樹合併便可。ip

10分鐘寫完即AC爽爽string

代碼:

 1 #include<algorithm>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<cstdio>
 5 #include<cmath>
 6 #include<queue>
 7 #define inf 2147483647
 8 #define eps 1e-9
 9 using namespace std; 10 typedef long long ll; 11 typedef double db; 12 struct node{ 13     int ls,rs,v; 14 }t[2000001]; 15 int n,m,q,u,v,cnt=0,fa[100001],rts[100001],num[100001],nmd[100001]; 16 char op[3]; 17 int ff(int u){ 18     return fa[u]==u?u:fa[u]=ff(fa[u]); 19 } 20 void updata(int &u,int l,int r,int x){ 21     if(!u)u=++cnt; 22     if(l==r){ 23         t[u].v=1; 24         return; 25  } 26     int mid=(l+r)/2; 27     if(x<=mid)updata(t[u].ls,l,mid,x); 28     else updata(t[u].rs,mid+1,r,x); 29     t[u].v=t[t[u].ls].v+t[t[u].rs].v; 30 } 31 int merge(int x,int y){ 32     if(!x||!y)return x|y; 33     t[x].ls=merge(t[x].ls,t[y].ls); 34     t[x].rs=merge(t[x].rs,t[y].rs); 35     t[x].v=t[t[x].ls].v+t[t[x].rs].v; 36     return x; 37 } 38 int query(int u,int l,int r,int k){ 39     if(l==r){ 40         return l; 41  } 42     int mid=(l+r)/2; 43     if(t[t[u].ls].v>=k)return query(t[u].ls,l,mid,k); 44     else return query(t[u].rs,mid+1,r,k-t[t[u].ls].v); 45 } 46 int main(){ 47     scanf("%d%d",&n,&m); 48     for(int i=1;i<=n;i++){ 49         scanf("%d",&num[i]); 50         fa[i]=nmd[num[i]]=i; 51  } 52     for(int i=1;i<=m;i++){ 53         scanf("%d%d",&u,&v); 54         int fu=ff(u),fv=ff(v); 55         if(fu!=fv){ 56             fa[fu]=fv; 57  } 58  } 59     for(int i=1;i<=n;i++){ 60         int fu=ff(i); 61         updata(rts[fu],1,n,num[i]); 62  } 63     scanf("%d",&q); 64     while(q--){ 65         scanf("%s%d%d",op,&u,&v); 66         if(op[0]=='Q'){ 67             int fu=ff(u); 68             if(t[rts[fu]].v<v){ 69                 puts("-1"); 70             }else printf("%d\n",nmd[query(rts[fu],1,n,v)]); 71         }else{ 72             int fu=ff(u),fv=ff(v); 73             if(fu!=fv){ 74                 fa[fu]=fv; 75                 rts[fv]=merge(rts[fu],rts[fv]); 76  } 77  } 78  } 79     return 0; 80 }
相關文章
相關標籤/搜索