P1486 [NOI2004]郁闷的出纳员(线段树或splay)

题目链接:P1486 [NOI2004]郁闷的出纳员
题意:中文题意

一、权值线段树

注意到加值与减值都是对整体加减,故可以记录修改量 c h a n g e change change,表示所有的 + k i +k_i +ki − k i -k_i ki,那么插值可以看做插一个权值为 x − c h a n g e x-change xchange的点,工资下降可看做是对值域区间 [ 0 , m i n n − c h a n g e − 1 ] [0,minn-change-1] [0,minnchange1]清零,第k大可看做是查询值域区间 [ m i n n − c h a n g e , + o o ] [minn-change,+oo] [minnchange,+oo]内的第k大。
当然为了防止数字越到负数上,可以对维护的权值先全部加一个超大值。

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

const int maxn=4e5+7;
ll num[maxn<<2|1];
bool vis[maxn<<2|1];
const int cc=2e5;

void pushup(int k){ num[k]=num[k<<1]+num[k<<1|1]; }
void pushdown(int k){
    if(vis[k]){
        vis[k<<1]=vis[k<<1|1]=vis[k];
        num[k<<1]=num[k<<1|1]=0;
        vis[k]=0;
    }
}

void insert(int l,int r,int k,int id){
    if(l==r){
        ++num[k];
        return ;
    }
    int mid=l+r>>1;
    pushdown(k);
    if(id<=mid) insert(l,mid,k<<1,id);
    else insert(mid+1,r,k<<1|1,id);
    pushup(k);
}

int del(int l,int r,int k,int L,int R){
    int res=0;
    if(l>=L&&r<=R){
        vis[k]=1;
        res=num[k];
        num[k]=0;
        return res;
    }
    int mid=l+r>>1;
    pushdown(k);
    if(L<=mid) res+=del(l,mid,k<<1,L,R);
    if(R>mid) res+=del(mid+1,r,k<<1|1,L,R);
    pushup(k);
    return res;
}

int query(int l,int r,int k,int L,int R){
    if(l>=L&&r<=R) return num[k];
    int mid=l+r>>1; pushdown(k);
    int res=0;
    if(L<=mid) res+=query(l,mid,k<<1,L,R);
    if(R>mid) res+=query(mid+1,r,k<<1|1,L,R);
    return res;
}
int kth(int l,int r,int k,int id,int val){
    if(l==r){
        if(num[k]<val) return -1;
        return l;
    }
    pushdown(k);
    int mid=l+r>>1;
    if(id>mid) return kth(mid+1,r,k<<1|1,id,val);
    else{
        int vv=query(mid+1,r,k<<1|1,mid+1,r);
        if(vv>=val) return kth(mid+1,r,k<<1|1,id,val);
        return kth(l,mid,k<<1,id,val-vv);
    }
}
char s[9];
#define debug(x) cout<<(#x)<<" : "<<(x)
int main(){
    int q,mm=0,x;
    ll minn;
    ll change=0;
    scanf("%d%lld",&q,&minn);
    while(q--){
        scanf("%s%d",s,&x);
        if(s[0]=='I'){
            if(x<minn) continue;
            insert(0,maxn-1,1,x+cc-change);
        }
        else if(s[0]=='A'){
            change+=x;
        }
        else if(s[0]=='S'){
            change-=x;
            //debug(minn-change+cc-1)<<endl;
            if(minn-change+cc-1>=0) mm+=del(0,maxn-1,1,0,minn-change+cc-1);
        }
        else{
            int res=kth(0,maxn-1,1,max(minn-change+cc,0LL),x);
            if(res==-1) printf("-1\n");
            else printf("%d\n",res+change-cc);
        }
    }
    printf("%d\n",mm);

    return 0;
}

二、splay

就直接维护splay,支持插入,删除,打懒标记。
暂时还没学完splay,是个口胡王者。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值