划分树

划分树
/*
划分树,求解给定区间[l, r]的第k小。
和归并是相反,相当于把归并树倒过来。
当访问到节点t时,sum[bit][i](left <= i <= right)表示从第left个数到第i个数中
有sum[bit][i]个数进入了左子树。
假如我们在区间[left, right]中求解[l, r]中的第k小的时候(left <= l <= r <= right),
看在区间[l,r]中有多少个数进入了左子树,如果有s个,如果s>=k,则递归到左节点,但是
要注意的是,当访问的左节点的时候,求解的区间[l, r]要发生变化 ,即找到区间[l, r]中
第一次出现在左子树的位置ll,和最后一次出现在左子树的位置rr,然后访问左子树的区间
[ll, rr],一直到left=right,返回元数列sa[left]为所求。 

*/


#include 
< iostream >
#include 
< algorithm >
using   namespace  std;
#define  MAX_SIZE 100010

struct  Tree
{
    
int  l, r, bit;
}tree[
3   *  MAX_SIZE];

int  sum[ 24 ][MAX_SIZE];  // 记录划分过程的数组,需要空间为n*logn 
int  a[ 2 ][MAX_SIZE];    //  滚动数组, 在划分过程中,保存上一层的序列,最开始时将
                     
// 将数组存放到a[0][i]中 
int  sa[MAX_SIZE];     //  排序数组 

void  MakeTree( int  k,  int  bit,  int  l,  int  r)
{
     tree[k].bit 
=  bit;
     tree[k].l 
=  l, tree[k].r  =  r;
     
if  (l  ==  r)
        
return  ;
     
int  inf  =  (bit  &   1 );
     
int  low  =  (l  +  r)  >>   1 ;
     
int  temp  =   0 ;
     
int  t  =   0 ;
     
int  c  =   0 ;
     
while  (low  -  temp  >=  l  &&  sa[low  -  temp]  ==  sa[low])temp ++ ;
     
int  i  =  l, j  =  low  +   1 ;
     
for  (;l  <=  r; l ++ )
     {
         
if  (a[inf][l]  <  sa[low])
         {
             c
++ ;
             sum[bit][l] 
=  c;
             a[
1   -  inf][i ++ =  a[inf][l];
         }
         
else   if  (a[inf][l]  ==  sa[low]  &&  t  <  temp)
         {
             c
++ ;
             sum[bit][l] 
=  c;
             a[
1   -  inf][i ++ =  a[inf][l];
             t
++ ;
         }
         
else  
         {
              sum[bit][l] 
=  c;
              a[
1   -  inf][j ++ =  a[inf][l];
         }
     }
     l 
=  tree[k].l;
     MakeTree(
2   *  k, bit  +   1 , l, low);
     MakeTree(
2   *  k  +   1 , bit  +   1 , low  +   1 , r);
}

int  Find_rank( int  k,  int  l,  int  r,  int  t)
{
    
int  bit  =  tree[k].bit;
    
int  left  =  tree[k].l, right  =  tree[k].r;
    
int  low  =  (left  +  right)  >>   1 ;
    
if  (right  ==  left)
    {
      
return  sa[left];
    }
    
int  s;
    
if  (l  ==  left)
       s 
=  sum[bit][r];
    
else
       s 
=  sum[bit][r]  -  sum[bit][l  -   1 ];
    
if  (s  >=  t)
    {
       
if  (l  ==  left)
       
return  Find_rank( 2   *  k, left, left  +  sum[bit][r]  -   1 , t);
       
else
       
return  Find_rank( 2   *  k, left  +  sum[bit][l  -   1 ], left  +  sum[bit][r]  -   1 , t);
    }
    
else
    {
        
if  (l  ==  left)
        
return  Find_rank( 2   *  k  +   1 , low  +   1 , low  +   1   +  r  -  l  -  s, t  -  s);
        
else
        
return  Find_rank( 2   *  k  +   1 , low  +   1   +  l  -  left  -  sum[bit][l  -   1 ], low  +  r  -  left  +   1   -  sum[bit][r], t  -  s);
    }
}

int  main()
{
    
int  i, j, k, l, m, n, t, r;
    
while  (scanf( " %d%d " & n,  & m)  !=  EOF)
    {
          
          memset(sum, 
0 sizeof (sum));
          
for  (i  =   1 ; i  <=  n; i ++ )
          {
              scanf(
" %d " & a[ 0 ][i]);
              sa[i] 
=  a[ 0 ][i];
          }
          sort(sa 
+   1 , sa  +  n  +   1 );
          MakeTree(
1 0 1 , n);
          
          
for  (i  =   0 ; i  <  m; i ++ )
          {
              scanf(
" %d%d%d " & l,  & r,  & k);
              printf(
" %d\n " , Find_rank( 1 , l, r, k));
          }
    }
    
return   0 ;
}

你可能感兴趣的:(划分树)