权值线段树+动态开点[NOI2004]郁闷的出纳员

  

#include<iostream>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#define rep(i,j,k) for(int i=j;i<=k;i++)
#define per(i,j,k) for(int i=j;i>=k;i--)
using namespace std;
const int maxx = 2e5+50;
int lson[maxx*18],rson[maxx*18],sum[maxx*18];
int tot=1,root=1;
bool laze[maxx*18];
void push_down(int x){
    if(laze[x]){
        if(!lson[x])lson[x]=++tot;
        if(!rson[x])rson[x]=++tot;
        sum[lson[x]]=0;
        sum[rson[x]]=0;
        laze[lson[x]]=1;
        laze[rson[x]]=1;
        laze[x]=0;
    }
}
void inserts(int l,int r,int x,int &p){
    if(!p)p=++tot;
    if (l==r){
        sum[p]++;
        return;
    }
    int mid=(l+r)>>1;
    push_down(p);
    if (x<=mid){
        inserts(l,mid,x,lson[p]);
    }else {
        inserts(mid+1,r,x,rson[p]);
    }
    sum[p]=sum[lson[p]]+sum[rson[p]];
}
void update(int l,int r,int ul,int ur,int &p){
    if (!p)p=++tot;
    if (ul<=l && r<=ur){
       sum[p]=0;
       laze[p]=1;
       return;
    }
    push_down(p);
    int mid=(l+r)>>1;
    if(ul<=mid)update(l,mid,ul,ur,lson[p]);
    if(ur>mid)update(mid+1,r,ul,ur,rson[p]);
    sum[p]=sum[lson[p]]+sum[rson[p]];
}
int kth(int l,int r,int k,int &p){
    if(l==r){
        return l;
    }
    int mid=(l+r)>>1;
    push_down(p);
    if(k<=sum[lson[p]]){
        return kth(l,mid,k,lson[p]);
    }else {
        return kth(mid+1,r,k-sum[lson[p]],rson[p]);
    }
}
int main(){
  int n,m,w;
  int add=0,nowmin,num=0;
  char op[10];
  while(~scanf("%d%d",&n,&nowmin)){
     rep(i,1,n){
        scanf("%s%d",op,&w);
        if (op[0]=='I'){
            //减去影响后如果起薪小于工资下界
            if (w-add<nowmin)continue;
            //他的工资实际上应该是他的起
            inserts(-maxx,maxx,w-add,root);
            num++;
        }else if(op[0]=='A'){
            //偏移应该加上
            add+=w;
            //同时此时要求最低的工资降低
            nowmin-=w;
        }else if(op[0]=='S'){
            add-=w;
            nowmin+=w;
            //比最低工资低的值全部赋值为0
            update(-maxx,maxx,-maxx,nowmin-1,root);
        }else {
            //如果所有人被开除
            if(w>sum[1]){
                printf("-1\n");
                continue;
            }else {
            //查询剩下的第K大,并且要加上偏移
            //其实等价于查询当前第K大=总数-第K小+1
               printf("%d\n",kth(-maxx,maxx,sum[1]-w+1,root)+add);
            }
        }
     }
    printf("%d\n",num-sum[1]);
  }
  return 0;
}

 

posted @ 2019-08-12 11:01  bluefly-hrbust  阅读(175)  评论(0编辑  收藏  举报