POJ 2761 Feed the dogs Treap+离散处理

题目已说明任何两个区间不包含,也就是说对区间排序后的相邻两个区间L(i-1)<L(i) && R(i-1)<R(i)。那么离散化以后充分利用前后两个区间重叠的部分,多的去掉,少的补上。然后就是查询第k大了。


自己画了个图,对于第i个查询来说,红色部分就是重叠的部分不需要改,绿色部分是要从Treap中删掉的,蓝色部分是要再往Treap里加的。


吐个槽 : POJ中G++不支持INT_MAX


#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<vector>
#include<cmath>
#include<string>
#include<algorithm>
#include<set>
#include<map>
#include<cstring>
#include<queue>
#include<stack>
#include<list>

using namespace std;

const int maxn=100000+100;
const int maxm=50000+200;
const int maxnode=maxn;

struct Treap{
    int root,treapcnt,key[maxnode],priority[maxnode],
    childs[maxnode][2],cnt[maxnode],size[maxnode];

    void treap(){
        root=0;
        treapcnt=1;
        priority[0]=2147483648-2;
        size[0]=0;
    }

    void update(int x){
        size[x]=size[ childs[x][0] ]+cnt[x]+size[ childs[x][1] ];
    }

    void rotate(int &x,int t){
        int y=childs[x][t];
        childs[x][t]=childs[y][1-t];
        childs[y][1-t]=x;
        update(x);
        update(y);
        x=y;
    }

    void __insert( int &x,int k ){
        if(x){
            if(key[x]==k){
                cnt[x]++;
            }
            else{
                int t=key[x]<k;
                __insert(childs[x][t],k);
                if( priority[childs[x][t]]<priority[x] ){
                    rotate(x,t);
                }
            }
        }else{
            x=treapcnt++;
            key[x]=k;
            cnt[x]=1;
            priority[x]=rand();
            childs[x][0]=childs[x][1]=0;
        }
        update(x);
    }

    void __erase(int &x,int k){
        if(key[x]==k){
            if(cnt[x]>1){
                cnt[x]--;
            }
            else{
                if(childs[x][0]==0&&childs[x][1]==0){
                    x=0;
                    return ;
                }
                int t=priority[ childs[x][0] ]>priority[childs[x][1]];
                rotate(x,t);
                __erase(x,k);
            }
        }else{
            __erase(childs[x][key[x]<k],k);
        }
        update(x);
    }

    int __getkth(int &x,int k){
        if(k<=size[childs[x][0]] ){
            return __getkth(childs[x][0],k );
        }
        k-=size[childs[x][0]]+cnt[x];
        if(k<=0)return key[x];
        return __getkth(childs[x][1],k);
    }

    void insert( int k ){
        __insert(root,k);
    }

    void erase(int k){
        __erase(root,k);
    }

    int getkth(int k){
        return __getkth(root,k);
    }
};

struct query{
    int l,r,k;
    int id;
    bool operator<(const query &b)const{
        return l<b.l;
    }
}qs[maxm];


Treap treap;
int a[maxn];
int ans[maxm];


int main()
{
    int n,m;
    while(scanf("%d%d",&n,&m)!=EOF){
        treap.treap();
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&qs[i].l,&qs[i].r,&qs[i].k);
            qs[i].id=i;
        }
        sort(qs,qs+m);
        for(int i=0;i<m;i++){
            if(i==0){
                for(int j=qs[i].l;j<=qs[i].r;j++){
                    treap.insert(a[j]);
                }
            }else{
                for(int j=qs[i-1].l;j<qs[i].l;j++){
                    treap.erase(a[j]);
                }
                for(int j=qs[i-1].r+1;j<=qs[i].r;j++){
                    treap.insert(a[j]);
                }
            }
            ans[qs[i].id]=treap.getkth(qs[i].k);
        }
        for(int i=0;i<m;i++){
            printf("%d\n",ans[i]);
        }

    }

	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值