划分树 POJ2104

划分树

理解:建树的时候,bulid(int f,int e,int root,int d),在区间[f,e]中,将线段树左右端点(root的左右值)设为f和e。当前层是第d层,将下一层的左右子树分类好,即算出这一层在[f,e]区间的中值data[mid],之后小于data[mid]的值放d+1层的左边,大于data[mid]的值放d+1层的右边。建完树之后会打表将建树的过程在每一层记录下来。最多建20层,因为2^20已经足够存储很大的数列了。

update的时候通过递归,确定在下一层左右哪一个子树,递归到下一层的时候减小所求区间,直到区间长度为1时,返回区间值。

 

 1 #include <iostream>

 2 #include <string>

 3 #include <algorithm>

 4 #define MAX 100010

 5 #define DEPTH 20

 6 using namespace std;

 7 int lessMid[DEPTH][MAX];

 8 int seg[DEPTH][MAX];

 9 int data[MAX];

10 int n;

11 struct seg_tree

12 {

13     int l,r;

14 }tr[MAX*4];

15 void bulid(int f,int e,int root,int d)

16 {

17     tr[root].l=f;

18     tr[root].r=e;

19     if(f==e) return;

20     int mid=(f+e)>>1;

21     int lsame=mid-f+1;

22     for(int i=f;i<=e;i++){

23         if(seg[d][i]<data[mid])

24             lsame--;           //得出实际能放几个相同的数

25     }

26     int lson=f,rson=mid+1,same=0;

27     for(int i=f;i<=e;i++){

28         if(i==f)

29             lessMid[d][i]=0;            //表示在[f,e]内有几个数小于等于DATA[MID]

30         else lessMid[d][i]=lessMid[d][i-1];

31         if(seg[d][i]<data[mid]){

32             lessMid[d][i]++;

33             seg[d+1][lson++]=seg[d][i];

34         }else if(seg[d][i]>data[mid])

35             seg[d+1][rson++]=seg[d][i];

36         else{

37             if(same<lsame){

38                 same++;

39                 lessMid[d][i]++;

40                 seg[d+1][lson++]=seg[d][i];

41             }else seg[d+1][rson++]=seg[d][i];

42         }

43     }

44     bulid(f,mid,root*2,d+1);

45     bulid(mid+1,e,root*2+1,d+1);

46 }

47 int update(int f,int e,int root,int d,int cnt)

48 {

49     if(f==e) return seg[d][f];

50     int s;

51     int ss;

52     if(f==tr[root].l)

53     {

54         s=lessMid[d][e];

55         ss=0;

56     }else {

57         s=lessMid[d][e]-lessMid[d][f-1];  //表示在[f,e]内有几个小于等于data[MID]的个数

58         ss=lessMid[d][f-1];   //表示在[tr[root].l,f-1]内有几个小于等于data[MID]的个数

59     }

60     if(s>=cnt){

61         return update(tr[root].l+ss,tr[root].l+ss+s-1,root*2,d+1,cnt);  //区间长度减小1,d+1层的右端点是tr[root].l+ss+s-1

62 }else{ 63 int mid=(tr[root].l+tr[root].r)>>1; 64 int bb=f-tr[root].l-ss; 65 int b=e-f-s+1; 66 return update(mid+bb+1,mid+bb+b,root*2+1,d+1,cnt-s);  //区间长度减小1,d+1层的左端点是mid+bb+1


67 } 68 } 69 int main() 70 { 71 int m; 72 while(scanf("%d%d",&n,&m)!=EOF){ 73 for(int i=1;i<=n;i++){ 74 scanf("%d",&seg[1][i]); 75 data[i]=seg[1][i]; 76 } 77 sort(data+1,data+1+n); 78 bulid(1,n,1,1); 79 int l,r,cnt; 80 for(int i=0;i<m;i++){ 81 scanf("%d%d%d",&l,&r,&cnt); 82 printf("%d\n",update(l,r,1,1,cnt)); 83 } 84 } 85 return 0; 86 }

 

你可能感兴趣的:(poj)