[HNOI2004]宠物收养所 数据结构题

时间:2021-09-15 09:45:01

题目链接: http://www.lydsy.com/JudgeOnline/problem.php?id=1208

题意:  中文题就不说了,都能看明白

解法: 数据结构题,应该使用一个BST类型的数据结构来实现,bst,treap,avl,splay,sbt,等等都可以。

      我的解法是维护两个 spaly tree,A表示宠物,B表示收养者,

  对于 a = 0, 添加宠物时, 首先检查 B是否为空, 若执行 A.insert( a ), 否则,调用方法 B.deal( a ).

  deal( val ) 的思路:  若B中原本就有val值,则花费为0,直接删除key[x]=val的节点。 否则插入一个值为val的节点,

然后将其 splay( x, 0 ), 旋转到根, 然后找其 第一个比其小,与第一个比其大的,比较一下,小于或等于取左(题目要求),然后删除

选定的 l, 或者 r.   这时候还要删除多插入的 key[x] = val 的 x.  

  我是通过写了一个 remove( x ) 方法, 具体思路是,将其通过 splay( x, 0 ) 旋转到根,找其左或右第一个子节点 lch or rch, 则

lch or rch 存在则,必定 lch 无右孩子,rch 无左孩子,随便取一个替代x即可,处理下 指针关系即可。注意分情况考虑,因为lch or rch

可能不存在,此时需要分情况处理。

[HNOI2004]宠物收养所 数据结构题[HNOI2004]宠物收养所 数据结构题
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int mod = (int)1e6;
typedef long long LL;
const int N = 80100;
struct Splay{
    int ch[N][2], pre[N], sz[N];
    LL key[N];
    int rt, top;
    void rotate(int x,int d){
        int y = pre[x];
        ch[y][d^1] = ch[x][d];
        if( ch[x][d] ) pre[ch[x][d]] = y;
        if( pre[y] ) ch[pre[y]][ ch[pre[y]][1]==y ] = x;
        pre[x] = pre[y];
        ch[x][d] = y;
        pre[y] = x;
        push_up(y);
    }
    void splay(int x,int goal){
        while( pre[x] != goal ){
            int y = pre[x];
            if( pre[y] == goal ) rotate( x, ch[y][0]==x );
            else{
                int z = pre[y];
                int d1 = ch[z][0]==y, d2 = ch[y][0]==x;
                if( d1 == d2 ) rotate(y,d1),rotate(x,d2);
                else rotate(x,d2), rotate(x,d1);
            }    
        }    
        if(goal == 0) rt = x;    
        push_up(x);
    } 
    void push_up(int x){
        if( x ) sz[x] = 1+sz[ ch[x][0] ]+sz[ ch[x][1] ];    
    }    
    void NewNode(int &x,LL c,int f){
        x = ++top;
        ch[x][0]=ch[x][0]=0;
        pre[x]=f, key[x]=c, sz[x] = 1;
    }    
    void init(){
        ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;
        rt = top = 0;
    }
    void insert(int x, LL val, int f){
        if( x == 0 ){ // if tree is empty
            NewNode(rt,val,0);    
            return;    
        }                
        int d = val > key[x];
        if( ch[x][d] != 0 ) insert( ch[x][d], val, x );    
        else{
            NewNode( ch[x][d], val, x );
            splay( ch[x][d], 0 );    
        }
        push_up(x);    
    }
    int find(LL val){
        int x = rt;
        while(x){
            if( key[x] == val ) return x;
            x = ch[x][ val > key[x] ];
        }    
        return 0;    
    }    
    void remove(int x){
        splay(x,0);
        if( ch[x][0] ){
            int y = ch[x][0];
            while( ch[y][1] ) y = ch[y][1];
            splay( y, x );
            ch[y][1] = ch[x][1]; pre[y] = pre[x];
            if( ch[x][1] ) pre[ ch[x][1] ] = y;
            if( pre[x] ) ch[pre[x]][ch[pre[x]][1]==x] = y;
            if( x == rt ) rt = y;
            push_up(y);    
        }
        else if( ch[x][1] ){
            int y = ch[x][1];    
            while( ch[y][0] ) y = ch[y][0];
            splay( y, x );
            ch[y][0] = ch[x][0]; pre[y] = pre[x];
            if( ch[x][0] ) pre[ ch[x][0] ] = y;
            if( pre[x] ) ch[pre[x]][ch[pre[x]][1]==x] = y;
            if( x == rt ) rt = y;
            push_up(y);    
        }
        else rt = 0;
    }     
    LL deal(LL val){
        int x = find(val); LL sum;
        //printf("Find: x = %d\n", x );
        if( x ){ remove(x);    sum = 0; }
        else{
        //    printf("Deal pre:\n"); print(rt);    
            insert( rt, val, 0 );
        //    printf("Deal:\n"); print(rt);
        
            x = find(val);
            splay(x,0);    
            int l = ch[x][0], r = ch[x][1];
            while( l && ch[l][1] ) l = ch[l][1];
            while( r && ch[r][0] ) r = ch[r][0];
        //    printf("l = %d, r = %d\n", l, r );            
            if( l && r ){
                if( (val-key[l]) <= (key[r]-val) )
                    sum = val-key[l], remove(l);    
                else
                    sum = key[r]-val, remove(r);    
            }
            else if( l ){ sum = val-key[l], remove(l); }
            else if( r ){ sum = key[r]-val, remove(r); }
            remove(x);    
        }    
        return sum;    
    }
    
    void print(int x){
        if( x == 0 ){ printf("Empty!\n"); return; }
        if( ch[x][0] ) print( ch[x][0] );
        printf("x=%d, lch=%d, rch=%d, pre=%d, sz=%d, key=%lld\n",
                x,ch[x][0],ch[x][1],pre[x],sz[x],key[x]);
        if( ch[x][1] ) print( ch[x][1] );
    }
}A, B;

int main(){
    int n;
    while( scanf("%d", &n) != EOF){
        int a; LL b;
        LL res = 0;    
        A.init(); B.init();    
        for(int i = 0; i < n; i++){
            scanf("%d%lld", &a, &b);    
            if( a == 0 ){ // dog
                if( B.sz[ B.rt ] == 0 ) A.insert(A.rt,b,0);    
                else res += B.deal(b);    
        ///        printf("A:\n"); A.print( A.rt );    
        //        printf("B:\n"); B.print( B.rt );    
            }
            else{ // people
                if( A.sz[ A.rt ] == 0 ) B.insert(B.rt,b,0);
                else res += A.deal(b);
        //        printf("A:\n"); A.print( A.rt );    
        //        printf("B:\n"); B.print( B.rt );    
            }
            res %= mod;    
        }
        printf("%lld\n", res );    
    }
    return 0;
}
View Code