Pku 2761 Feed the dogs

Pku 2761 Feed the dogs

首先用平衡树做出来了
学了一下传说中SBT,比较好用,编码不是很难
能够写二叉查找树就会写一半了。

平衡树只维护当前的区间,然后查找当前区间的
第K元素。

所以首先把区间从小到大排序,这样可以保证每个
元素只插入一次,删除也只有一次。
如样例。 首先把 1-5  区间元素插入,
到第二个区间 2-7 时,把 1-2 删除, 5-7 插入

SBT插入和删除都是logn,总复杂度nlogn+ mlogm

代码
#include <iostream>

using namespace std;

typedef 
int Type;

struct SBNode{
    
int   size;
    Type  key;
    SBNode
* lchild, *rchild;
    SBNode(){}
    SBNode( SBNode
*l, SBNode*r, int s, Type k ):
        lchild(l), rchild(r), size(s), key(k) {}
};

class SBTree{
    
private:
        SBNode
* root;
        SBNode
* _null;
        
        
void left_rotate ( SBNode*& root );
        
void right_rotate( SBNode*& root );
        
void maintain( SBNode*& root, bool style );
        
void insert( SBNode*& root, Type key );
        
void erase ( SBNode*& root, Type key );
        
void clear ( SBNode* root );
        
    
public:
        SBTree ();
        
~SBTree();
        
        
void insert( Type key );       //  插入元素 
        void erase ( Type key );       //  删除元素
        Type get_rank( int k  );       //  获得第 k 个元素 
        void clear();                  //  清空 
};

Type SBTree::get_rank( 
int k ){
    SBNode
* tmp= root;
    
for( ;; ){
        
if( tmp->lchild->size> k ) tmp= tmp->lchild;
        
else if( k> tmp->lchild->size ){
            k
-= tmp->lchild->size+ 1;
            tmp
= tmp->rchild; }
        
else break;}
    
return tmp->key;
}

void SBTree::clear( SBNode* root ){
    
if( root!= _null ){
        clear( root
->lchild );
        clear( root
->rchild );
        delete root; }
}

void SBTree::clear(){
    clear(root); delete _null; }

void SBTree::erase( Type key ){
    erase( root, key ); }

void SBTree::erase( SBNode*& root, Type key ){
    
if( root== _null ) return;    root->size--;
    
if( root->key== key ){
        SBNode
* tmp;
        
if( root->lchild!= _null && root->rchild== _null ){
            tmp
= root;  root= tmp->lchild; delete tmp; }
        
else if( root->lchild== _null && root->rchild== _null ){
            tmp
= root; root= _null; delete tmp; }
        
else {
            tmp
= root->rchild; 
            
while( tmp->lchild!= _null ) tmp= tmp->lchild;
            root
->key= tmp->key; erase( root->rchild, tmp->key );}
    }
    
else if( key< root->key ) erase( root->lchild, key );
    
else erase( root->rchild, key );
}

void SBTree::insert( SBNode*& root, Type key ){
    
if( root== _null ){
     root
= new SBNode( _null, _null, 1, key ); return; }
    root
->size++;
    
if( key< root->key ) insert( root->lchild, key );
    
else                 insert( root->rchild, key );
    maintain( root, key
>= root->key );
}

void SBTree::insert( Type key ){
    insert( root, key ); }

SBTree::SBTree(){
    _null
= new SBNode();
    root
= _null; 
    root
->lchild= root->rchild= _null;
    root
->size= 0;
}

SBTree::
~SBTree(){
    clear();
}

void SBTree::left_rotate( SBNode*& root ){
    SBNode
* tmp= root->rchild;
    root
->rchild= tmp->lchild;  tmp->lchild= root;
    tmp
->size= root->size;
    root
->size= root->lchild->size+ root->rchild->size+ 1;
    root
= tmp;
}

void SBTree::right_rotate( SBNode*& root ){
    SBNode
* tmp= root->lchild;
    root
->lchild= tmp->rchild;  tmp->rchild= root;
    tmp
->size= root->size;
    root
->size= root->lchild->size+ root->rchild->size+ 1;
    root
= tmp;
}

void SBTree::maintain( SBNode*& root, bool style ){
    
if( root== _null ) return;
    
if!style ){
        
if( root->lchild->lchild->size> root->rchild->size )
        right_rotate( root );
        
else if( root->lchild->rchild->size> root->rchild->size ){
            left_rotate( root
->lchild );
            right_rotate( root );
           }
else return;
        }
    
else {
        
if( root->rchild->rchild->size> root->lchild->size )
        left_rotate( root );
        
else if( root->rchild->lchild->size> root->lchild->size ){
            right_rotate( root
->rchild );
            left_rotate( root ); 
        }
else return;
    }
   maintain(root
->lchild, false);  maintain(root->rchild, true);
   maintain(root, 
false);          maintain(root, true);
}

#define N 100011

struct Node{
    
int x, y, k, pos;
};

int n, m;
int d[N], ans[N];
Node q[N];

int cmp( const void* a, const void* b ){
    Node
* ta= (Node*)a;
    Node
* tb= (Node*)b;
    
    
if( ta->x== tb->x ) return ta->y- tb->y;
    
return ta->x- tb->x;
}

SBTree test;

int main()
{
    scanf(
"%d%d",&n,&m );
    
forint i= 1; i<= n; ++i )
    scanf(
"%d", d+ i );
    
    
forint i= 0; i< m; ++i )
    {
        scanf(
"%d%d%d"&q[i].x, &q[i].y, &q[i].k );
        q[i].pos
= i; }
    
    qsort( q, m, 
sizeof(q[0]), cmp );
    
    
forint i= q[0].x; i<= q[0].y; ++i )
    test.insert( d[i] );
    ans[ q[
0].pos ]= test.get_rank( q[0].k- 1 );
    
forint i= 1; i< m; ++i ){
        
        
if( q[i].x< q[i-1].y ){
            
forint j= q[i-1].x; j< q[i].x; ++j )
            test.erase( d[j] );
            
forint j= q[i-1].y+ 1; j<= q[i].y; ++j )
            test.insert( d[j] ); }
        
else {
            
forint j= q[i-1].x; j<= q[i-1].y; ++j )
            test.erase( d[j] );
            
forint j= q[i].x; j<= q[i].y; ++j )
            test.insert( d[j] );
        }
        ans[ q[i].pos ]
= test.get_rank( q[i].k- 1 );
    }
    
    
forint i= 0; i< m; ++i ) printf("%d\n", ans[i] );

    
return 0;
}




另外还用数状数组做了下

树状数组的做法和以上相似,只是首先要把离散化一
下, 稍微有些麻烦。插入相当于在树状数据对应元素
增加 1, 删除相当于增加 -1, 查找每 k 元素,相
当于找到 sum 等于 k的最小元素,这个可以二分sum
去求, 总复杂度为 mlogm+ nlognlogn。

不过好像求第k元素有一个 nlogn 的做法, 没学会
还得去看看。


代码
#include <stdio.h>
#include 
<stdlib.h>
#include 
<string.h>

#define lowbit(x) ( (x)&(-(x)) )
#define MAXN  100010

struct  FNode{ int data, index;   };
struct  SNode{ int x, y, k, idx;  };

int count[MAXN], ans[MAXN], inp[MAXN], pos[MAXN];
int n, m;
FNode d[MAXN];
SNode q[MAXN];

void init(){
    memset( count, 
0sizeof(count) );
}

void update( int pos, int value ){
    
while( pos<= n ){
        count[pos]
+= value;
        pos
+= lowbit(pos); }
}

int sum( int pos ){
    
int s= 0;
    
while( pos ){
        s
+= count[pos];
        pos
-= lowbit(pos);
    }
    
return s;
}

int cmpa( const void* a, const void* b ){
    FNode
* ta= (FNode*)a, *tb= (FNode*)b;
    
return ta->data- tb->data; }

int cmpb( const void* a, const void* b ){
    SNode
* ta= (SNode*)a, *tb= (SNode*)b;
    
    
if( ta->x== tb->x ) return ta->y- tb->y;
    
return ta->x- tb->x;
}

int bfind( int k ){
    
int left= 1, right= n+ 1, mdl;
    
while( left+ 1< right ){
        mdl
= ( left+ right )>> 1;
        
if( sum(mdl)>= k ) right= mdl;
        
else left = mdl;
    }
    
if( sum(left)== k ) return left;
    
return left+ 1;
}

int main(){
    init();
    scanf(
"%d%d",&n, &m );
    
forint i= 1; i<= n; ++i ) {
        scanf(
"%d"&d[i].data );
        inp[i]
= d[i].data;
        d[i].index
= i; }
    
    qsort( d
+ 1, n, sizeof(d[0]), cmpa );
    
forint i= 1; i<= n; ++i ) pos[ d[i].index ]= i;
        
    
forint i= 0; i< m; ++i ){
        scanf(
"%d%d%d",&q[i].x, &q[i].y, &q[i].k );
        q[i].idx
= i; }
    
    qsort( q, m, 
sizeof(q[0]), cmpb );
    
forint i= q[0].x; i<= q[0].y; ++i )
    update( pos[i], 
1 ); 
    
    ans[ q[
0].idx ]= inp[ d[ bfind( q[0].k ) ].index ];
    
forint i= 1; i< m; ++i ){
        
if( q[i].x< q[i-1].y ){
            
forint j= q[i-1].x; j< q[i].x; ++j )
            update( pos[j], 
-1 );
            
forint j= q[i-1].y+ 1; j<= q[i].y; ++j )
            update( pos[j],  
1 );
        }
        
else {
            
forint j= q[i-1].x; j<= q[i-1].y; ++j )
            update( pos[j], 
-1 );
            
forint j= q[i].x; j<= q[i].y; ++j )
            update( pos[j],  
1 );
        }
        ans[ q[i].idx ]
= inp[ d[ bfind( q[i].k ) ].index ];
    }
    
    
forint i= 0; i< m; ++i ) printf("%d\n", ans[i] );

    
return 0;
}


这题还可以用其它数据结构做出
确实是一道练习数据结构的好题啊

你可能感兴趣的:(Pku 2761 Feed the dogs)