poj2104_划分树

在算法篇介绍过求这样的某一个范围内第k大的数的三种方法。

分治方法,对于求一组范围内的值可以考虑。但是求多组的时候就不行了,因为这种方法会改变原数组的排序。如果要有多组询问时,就必须赋值到另外一个数组中,结果TLE.

代码:

View Code
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <memory.h>
 4 #include <algorithm>
 5 using namespace std;
 6 
 7 const int maxnum=100005;
 8 int array[maxnum];
 9 int a[maxnum];
10 
11 int patition(int p,int r)
12 {
13     int temp=a[r];
14     int i=p-1;
15     int j,t;
16     for(j=p;j<=r-1;j++)
17     {
18         if(a[j]<=temp)
19         {
20             i++;
21             t=a[i];
22             a[i]=a[j];
23             a[j]=t;
24         }
25     }
26     t=a[i+1];
27     a[i+1]=a[r];
28     a[r]=t;
29     return i+1;
30 }
31 
32 int select(int p,int r,int i)
33 {
34     if(p==r)
35         return a[p];
36     int q=patition(p,r);
37     int k=q-p+1;
38     if(k==i)
39         return a[q];
40     else if(i<k)
41         return select(p,q-1,i);
42     else
43         return select(q+1,r,i-k);
44 }
45 
46 void function(int p,int r,int i)
47 {
48     int k;
49     int cnt=0;
50     for(k=p;k<=r;k++)
51         a[cnt++]=array[k];
52 //    for(k=0;k<cnt;k++)
53 //        cout<<a[k]<<" ";
54 //    cout<<endl;
55     printf("%d\n",select(0,cnt-1,i));
56 }
57 
58 int main()
59 {
60     int n,m;
61     scanf("%d%d",&n,&m);
62     int i,p,q,j;
63     for(i=0;i<n;i++)
64         scanf("%d",&array[i]);
65     while(m--)
66     {
67         scanf("%d%d%d",&p,&q,&j);
68         function(p-1,q-1,j);
69     }
70     return 0;
71 }
72 
73 
74 /*
75 6 1
76 1 1 1 1 1 1
77 3 5 2
78 */

 

划分树方法可以用于求多组的情况,且查询时间复杂度O(lgn)

代码:

View Code
  1 #include <iostream>
  2 #include <stdio.h>
  3 #include <algorithm>
  4 #include <memory.h>
  5 using namespace std;
  6 const int maxnum=100005;
  7 struct node
  8 {
  9     int array[maxnum];
 10     int sum[maxnum];
 11 }tree[20];   //树有10层
 12 int sorted[maxnum];
 13 
 14 void Build_tree(int cur,int l,int r)
 15 {
 16     if(l==r)
 17         return ;
 18     int m=(l+r)/2;
 19     int i;
 20 
 21     int lsame=m-l+1; //这是往cur+1左子树中一共放入的节点,其中小于中值的一定在左子树中,等于中值的可能在左子树,也可能在右子树
 22     for(i=l;i<=r;i++)
 23         if(tree[cur].array[i]<sorted[m])
 24             lsame--;//与中值相同的放在左子树中的个数
 25 
 26     int lnum=l,rnum=m+1;
 27     for(i=l;i<=r;i++)
 28     {
 29         if(i==l)
 30             tree[cur].sum[i]=0;
 31         else
 32             tree[cur].sum[i]=tree[cur].sum[i-1];
 33         if(tree[cur].array[i]<sorted[m])
 34         {
 35             tree[cur].sum[i]++;
 36             tree[cur+1].array[lnum++]=tree[cur].array[i];
 37         }
 38         else if(tree[cur].array[i]>sorted[m])
 39             tree[cur+1].array[rnum++]=tree[cur].array[i];
 40         else   //if(tree[cur].array[i]==sorted[m])
 41         {
 42             if(lsame>0)
 43             {
 44                 lsame--;
 45                 tree[cur].sum[i]++;
 46                 tree[cur+1].array[lnum++]=tree[cur].array[i];
 47             }
 48             else
 49                 tree[cur+1].array[rnum++]=tree[cur].array[i];
 50         }
 51     }
 52     Build_tree(cur+1,l,m);
 53     Build_tree(cur+1,m+1,r);
 54 }
 55 
 56 int find(int cur,int st,int ed,int l,int r,int k)
 57 {
 58     //cout<<cur<<" "<<st<<" "<<ed<<" "<<l<<" "<<r<<" "<<k<<endl;
 59     if(l==r)
 60         return tree[cur].array[l];
 61     int m=(st+ed)/2;
 62     int lnum,rnum;
 63     if(l-1<st)
 64         lnum=0;
 65     else
 66         lnum=tree[cur].sum[l-1];
 67     rnum=tree[cur].sum[r];
 68     if(rnum-lnum>=k)//表示有几个点进入左子树
 69         return find(cur+1,st,m,st+lnum,st+rnum-1,k);
 70     else
 71         return find(cur+1,m+1,ed,m+1+(l-st-lnum),m+1+(r-st-rnum),k-(rnum-lnum));
 72 }
 73 
 74 
 75 int main()
 76 {
 77     int n,m;
 78     scanf("%d%d",&n,&m);
 79     int i;
 80     for(i=1;i<=n;i++)
 81     {
 82         scanf("%d",&tree[0].array[i]);
 83         sorted[i]=tree[0].array[i];
 84     }
 85     sort(sorted+1,sorted+n+1);
 86     Build_tree(0,1,n);
 87 
 88     int p,r,k;
 89     int res;
 90     while(m--)
 91     {
 92         scanf("%d%d%d",&p,&r,&k);
 93         res=find(0,1,n,p,r,k);
 94         printf("%d\n",res);
 95     }
 96 
 97     return 0;
 98 }
 99 
100 
101 /*
102 6 1
103 1 1 1 1 1 1
104 2 4 2
105 10 7 2 5 1 4 6
106 */
107 
108 
109 //    for(i=0;i<4;i++)
110 //    {
111 //        cout<<i<<endl;
112 //        for(j=1;j<maxnum;j++)
113 //            cout<<tree[i].array[j]<<" ";
114 //        cout<<endl;
115 //        for(j=1;j<maxnum;j++)
116 //            cout<<tree[i].sum[j]<<" ";
117 //        cout<<endl;
118 //    }


tju oj2722

posted @ 2012-08-07 17:32  pushing my way  阅读(263)  评论(0编辑  收藏  举报