划分树 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 }

 

posted @ 2012-08-04 12:29  HUJJ  阅读(290)  评论(0编辑  收藏  举报