POJ2761-Treap

Description

Wind loves pretty dogs very much, and she has n pet dogs. So Jiajia has to feed the dogs every day for Wind. Jiajia loves Wind, but not the dogs, so Jiajia use a special way to feed the dogs. At lunchtime, the dogs will stand on one line, numbered from 1 to n, the leftmost one is 1, the second one is 2, and so on. In each feeding, Jiajia choose an inteval[i,j], select the k-th pretty dog to feed. Of course Jiajia has his own way of deciding the pretty value of each dog. It should be noted that Jiajia do not want to feed any position too much, because it may cause some death of dogs. If so, Wind will be angry and the aftereffect will be serious. Hence any feeding inteval will not contain another completely, though the intervals may intersect with each other.

Your task is to help Jiajia calculate which dog ate the food after each feeding.

解题思路

题目意思大致就是给出一个序列,每次询问区间[i,j]的第k大的数,并且询问的区间不会重叠或覆盖
如果没有最后这个条件,那么这题就需要用线段树套Treap来做,那么最后这个条件有什么用?显然,题目在提示我们用离线算法,因为最后这个性质只在离线算法里有用,可以把线段排序,这样,每次Treap中存的都是前一条线段,而线段不会重叠或覆盖,这样,要使Treap中存的是当前的线段,只要从前一条线段的尾部删去不在当前线段中的元素,然后加上当前线段尾部不在前一条线段中的元素。最后注意输出要按照输入顺序。

附上代码

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define maxn 100006
#define maxm 50006
using namespace std;
struct node{
    node* ch[2];
    int key,f,s,num;
    void maintain(){
        s=num;
        if(ch[0]!=NULL)s+=ch[0]->s;
        if(ch[1]!=NULL)s+=ch[1]->s;
    }
}treap[maxn];
typedef node* pnode;
node nul;
pnode root,len,null=&nul;
void rot(pnode &p,int d){
    pnode k=p->ch[d^1];p->ch[d^1]=k->ch[d];k->ch[d]=p;
    p->maintain();k->maintain();p=k;
}
pnode newnode(int key){
    len->ch[0]=len->ch[1]=null;len->key=key;len->s=len->num=1;len->f=rand();
    return len++;
}
void insert(pnode &p,int x){
    if(p==null)p=newnode(x);else
    if(p->key==x)p->s++,p->num++;else{
        int d=p->key<x;
        insert(p->ch[d],x);
        if(p->ch[d]->f<p->f)rot(p,d^1);
    }
    p->maintain();
}
void erase(pnode &p,int x){
    if(p->key==x){
        if(p->num>1)p->num--;else
        if(p->ch[0]==null)p=p->ch[1];else
        if(p->ch[1]==null)p=p->ch[0];else{
            int d=p->ch[0]->f>p->ch[1]->f;
            rot(p,d^1);
            erase(p->ch[d^1],x);
        }
    }else{
        int d=p->key<x;
        erase(p->ch[d],x);
    }
    p->maintain();
}
int getn(pnode p,int x){
    if(p->ch[0]->s+1<=x&&p->ch[0]->s+p->num>=x)return p->key;else
    if(p->ch[0]->s>=x)return getn(p->ch[0],x);else
                      return getn(p->ch[1],x-p->ch[0]->s-p->num);
}
void print(pnode p){
    if(p==null)return;
    print(p->ch[0]);
    for(int i=1;i<=p->num;i++) printf("%d ",p->key);
    print(p->ch[1]);
}
struct data{
    int s,t,k,id,ans;
}b[maxm];
int n,m,a[maxn];
bool cmp_s(const data x,const data y){
    return x.s<y.s;
}
bool cmp_id(const data x,const data y){
    return x.id<y.id;
}
int main(){
    freopen("feedog.in","r",stdin);
    freopen("feedog.out","w",stdout);
    len=treap;root=null;null->ch[0]=null->ch[1]=null;null->s=null->num=0;
//  scanf("%d",&n);
//  for(int i=1;i<=n;i++){
//      int x,y;
//      scanf("%d%d",&x,&y);
//      if(x==1)insert(root,y);else
//      if(x==2)erase(root,y);else
//              printf("%d\n",getn(root,y));
//      printf("Treap=");print(root);printf("\n");
//  }
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    for(int i=1;i<=m;i++){
        scanf("%d%d%d",&b[i].s,&b[i].t,&b[i].k);
        if(b[i].s>b[i].t)swap(b[i].s,b[i].t);
        b[i].id=i;
    }
    sort(b+1,b+1+m,cmp_s);b[0].s=1e9;b[0].t=-1e9;
    for(int i=1;i<=m;i++){
        int s=min(b[i-1].t,b[i].s-1),t=max(b[i-1].t+1,b[i].s);
        for(int j=b[i-1].s;j<=s;j++)erase(root,a[j]);
        for(int j=t;j<=b[i].t;j++)insert(root,a[j]);
        b[i].ans=getn(root,b[i].k);
//      printf("%d %d\n",b[i].s,b[i].t);
//      printf("Treap=");print(root);printf("\n");
    }
    sort(b+1,b+1+m,cmp_id);
    for(int i=1;i<=m;i++) printf("%d\n",b[i].ans);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值