1. 程式人生 > >B20J_2733_[HNOI2012]永無鄉_權值線段樹合並

B20J_2733_[HNOI2012]永無鄉_權值線段樹合並

排名 color pos 元素 res == can find Language

B20J_2733_[HNOI2012]永無鄉_權值線段樹合並

Description:n座島,編號從1到n,每座島都有自己的獨一無二的重要度,按照重要度可以將這n座島排名,名次用1到 n來表示。某些島之間由巨大的橋連接,通過橋可以從一個島到達另一個島。現在有兩種操作:B x y表示在島 x與島y之間修建一座新橋。Q x k表示詢問當前與島 x連通的所有島中第k重要的是哪座島,即所有與島 x連通的島中重要度排名第 k小的島是哪座,請你輸出那個島的編號。

對於100%的數據n≤100000,m≤n,q≤300000。

分析:讀懂題後發現是一道線段樹合並的裸題。Q操作顯然是權值線段樹求區間第k小元素,B操作是合並。

直接開發現開不下,需要動態開點,一開始要開nlogn個結點。

合並操作:

1 int merge(int x,int y)
2 {
3     if(!x)return y;
4     if(!y)return x;
5     lson[x]=merge(lson[x],lson[y]);
6     rson[x]=merge(rson[x],rson[y]);
7     t[x]=t[lson[x]]+t[rson[x]]; 
8     return x;
9 }

代碼:

  1 #include <stdio.h>
  2 #include <string.h>
  3 #include <algorithm>
  4
using namespace std; 5 const int N=3262145; 6 int tree[N],lson[N],rson[N],t[N],mp[N],fa[N],idx[N],cnt; 7 int n,m,k; 8 char s[10]; 9 int find(int x) 10 { 11 return fa[x]==x?x:fa[x]=find(fa[x]); 12 } 13 void bt(int l,int r,int val,int &pos) 14 { 15 if(pos==0)pos=++cnt; 16
if(l==r) 17 { 18 t[pos]=1; 19 return ; 20 } 21 int mid=l+r>>1; 22 if(val<=mid)bt(l,mid,val,lson[pos]); 23 else bt(mid+1,r,val,rson[pos]); 24 t[pos]=t[lson[pos]]+t[rson[pos]]; 25 } 26 int merge(int x,int y) 27 { 28 if(!x)return y; 29 if(!y)return x; 30 lson[x]=merge(lson[x],lson[y]); 31 rson[x]=merge(rson[x],rson[y]); 32 t[x]=t[lson[x]]+t[rson[x]]; 33 return x; 34 } 35 int query(int l,int r,int k,int pos) 36 { 37 if(l==r||k==0) 38 { 39 return mp[l]; 40 } 41 int mid=l+r>>1; 42 if(t[pos]<k)return -1; 43 if(t[lson[pos]]>=k) 44 { 45 return query(l,mid,k,lson[pos]); 46 } 47 else 48 { 49 return query(mid+1,r,k-t[lson[pos]],rson[pos]); 50 } 51 } 52 int main() 53 { 54 scanf("%d%d",&n,&m); 55 for(int i=1;i<=n;i++) 56 { 57 fa[i]=i; 58 } 59 for(int i=1;i<=n;i++) 60 { 61 scanf("%d",&idx[i]); 62 mp[idx[i]]=i; 63 } 64 for(int i=1;i<=n;i++) 65 { 66 tree[i]=++cnt; 67 bt(1,n,idx[i],tree[i]); 68 } 69 int x,y; 70 for(int i=1;i<=m;i++) 71 { 72 scanf("%d%d",&x,&y); 73 int dx=find(x),dy=find(y); 74 if(dx!=dy) 75 { 76 fa[dy]=dx; 77 tree[dx]=merge(tree[dx],tree[dy]); 78 } 79 } 80 scanf("%d",&k); 81 while(k--) 82 { 83 scanf("%s%d%d",s,&x,&y); 84 int dx=find(x); 85 if(s[0]==Q) 86 { 87 printf("%d\n",query(1,n,y,tree[dx])); 88 } 89 else 90 { 91 int dx=find(x),dy=find(y); 92 if(dx!=dy) 93 { 94 fa[dy]=dx; 95 tree[dx]=merge(tree[dx],tree[dy]); 96 } 97 } 98 } 99 } 100 101 /*************************************************************** 102 Problem: 2117 103 User: 20170105 104 Language: C++ 105 Result: Accepted 106 Time:644 ms 107 Memory:90164 kb 108 ****************************************************************/

B20J_2733_[HNOI2012]永無鄉_權值線段樹合並