程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> POJ 2104 劃分樹學習基礎題

POJ 2104 劃分樹學習基礎題

編輯:C++入門知識

題意:給出n個數字,和m次詢問,每次詢問區間【a,b】中第k大的數字,並且輸出。 這裡用到了一種數據結構,劃分樹。 劃分樹指的是,每一個節點保存區間[l,r]所有元素,元素排列順序與原數組相同,但是兩個子樹的元素為該節點所有元素排序後前(r-l+1)/2個進入左子樹,其余的到右子樹,同時維護一個sum域,sum[i]表示l--i這些點中有多少個進入了左子樹。 關於其查找,在[l,r]區間內,查找第k大數,t是該節點,tree[t].l,tree[t].r是該節點的左右區間。mid是區間中值。 1、sum[r]-sum[l-1]>=k,查找LL(t),區間對應為[ tree[t].l+sum[l-1] , tree[t].l+sum[r]-1 ] 2、sum[r]-sum[l-1]<k,查找RR(t),區間對應為[ mid+1+l-tree[t].l-sum[l-1] , mid+1+r-tree[t].l-sum[r] ] 具體見代碼 [cpp]   #include <iostream>   #include <cstdio>   #include <algorithm>   #include <string>   #include <cmath>   #include <cstring>   #include <queue>   #include <set>   #include <vector>   #include <stack>   #include <map>   #include <iomanip>   #define PI acos(-1.0)   #define Max 100005   #define inf 1<<28   #define LL(x) (x<<1)   #define RR(x) (x<<1|1)   #define FOR(i,s,t) for(int i=(s);i<=(t);++i)   #define ll long long   #define mem(a,b) memset(a,b,sizeof(a))   #define mp(a,b) make_pair(a,b)   using namespace std;      int lessmid[20][Max];//在區間內小於mid值的個數。   int seg[20][Max];   int num[Max];   struct seg_tree   {       int l ,r ;   } tree[Max*4];   void build_tree(int l,int r, int u,int d)   {       tree[u].l = l, tree[u].r = r;       if(l == r)return ;       int mid = l + r >> 1;       int issame = mid - l + 1;//左邊一共可以有多少元素       for (int i = l ; i <= r ; i ++)           if(seg[d][i] < num[mid])//小於中間值的全部放在左邊               issame --;//issame-- ,表示這個值可以放在左邊,那麼左邊的剩余總數減少。               //最終issame總數是表示放等於中值的數字的個數。       int lpos = l ,rpos = mid + 1;       for (int i = l ; i <= r ; i ++)       {           if( i == l )               lessmid[d][i] = 0;//lessmid[d][i]記錄在第d層,[l,i]之間小於等於中值的數的個數。           else               lessmid[d][i] = lessmid[d][i-1];           if(seg[d][i] < num[mid])           {               lessmid[d][i] ++;//小於中值,計數加               seg[d+1][lpos++] = seg[d][i];//將此數放到左邊           }           else if(seg[d][i] > num[mid])           {               seg[d+1][rpos++] = seg[d][i];//同理           }           else//若相等,則需用到上面的issame元素.           {               if(issame > 0)//如果issame > 0 ,那麼左邊還沒放滿,則可以將等於中值的數放到左邊。               {                   issame --;                   lessmid[d][i]++;//這裡加的就是等於中值的個數。                   seg[d+1][lpos++] = seg[d][i];               }               else                   seg[d+1][rpos++] = seg[d][i];           }       }       build_tree(l,mid,LL(u),d+1);       build_tree(mid+1,r,RR(u),d+1);   }      int update(int l,int r,int u,int d,int cnt)   {       if(l == r)return seg[d][l];       int num1 ,num2;       if(l == tree[u].l)       {           num1 = lessmid[d][r];           num2 = 0;       }       else       {           num1 = lessmid[d][r] - lessmid[d][l-1];//[l,r]的小於等於中值的個數,放到左邊           num2 = lessmid[d][l-1];//[tree[u].l,l-1]的小於等於中值的個數,放到左邊       }          if(num1 >= cnt)       {           return update(tree[u].l + num2,tree[u].l + num1 + num2 - 1,LL(u),d+1,cnt);       }       else       {           int mid = tree[u].l + tree[u].r >> 1;           int num4 = l - tree[u].l - num2;//[tree[u].l , l - 1]放到右邊的總數。           int num3 = r - l + 1- num1 ;//[l,r]放到右邊的總數。           return update(mid + num4 + 1 , mid + num3 +num4 ,RR(u),d+1 ,cnt - num1);       }   }      int main()   {       int n , m ;       cin >> n >> m ;       for (int i = 1 ; i <= n ; i ++)       {           scanf("%d",&num[i]);           seg[1][i] = num[i];       }       sort(num + 1,num + n + 1 );       build_tree(1,n,1,1);       while(m --)       {           int a, b ,c;           scanf("%d%d%d",&a,&b,&c);           printf("%d\n",update(a,b,1,1,c));       }       return 0;   }  

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved