1. 程式人生 > >[luogu1486][NOI2004]鬱悶的出納員

[luogu1486][NOI2004]鬱悶的出納員

傳送門

看到這題覺得是平衡樹,因為有查詢第k大和插入刪除操作。

但是我不會平衡樹啊……所以拿樹狀陣列寫了一個偽平衡樹。

對於插入操作,直接插,但是要減掉一個rec值。這個rec是什麼意思等下說。

對於刪除操作,直接刪就行了。

對於A,我們肯定不行把所有數字都加一遍,於是利用rec,使rec這個變數加上修改值。所以員工真正的工資 = 他們的值 + rec

對於S,同理。但是這裡我們需要不斷查詢最小值,和工資標準比較,然後開始刪。

對於查詢操作,直接查第k大即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
#define MAXN 600005
#define lowbit(x) (x&(-x))

struct disc {
    
    long long temp[MAXN],num[MAXN];
    int tot,cnt;
    disc() : tot(0),cnt(0) {}

    void add(long long x) {
        temp[++cnt] = x;
    }

    void unique() {
        std::sort(temp+1,temp+1+cnt);
        temp[0] = -2147483647;
        for(int i=1;i<=cnt;++i) 
            if(temp[i]!=temp[i-1]) num[++tot] = temp[i];
    }

    int sub(long long x) {
        int l = 1,r = tot;
        while(l<r) {
            int mid = (l+r+1)>>1;
            if(num[mid]>x) r = mid - 1;
            else l = mid;
        }
        return l;
    }

}d;

struct record {
    int num;
    char opt;
}R[MAXN];

int C[MAXN];
int N,line,count = 0,ans = 0;
long long rec = 0;

inline char get_opt() {
    char ch = getchar();
    while(ch!='I'&&ch!='A'&&ch!='S'&&ch!='F') ch = getchar();
    return ch;
}

inline int read() {
    char ch = getchar(); int num = 0;
    while(ch>'9'||ch<'0') ch = getchar();
    while(ch>='0'&&ch<='9') num = num*10+ch-'0' , ch = getchar();
    return num;    
}

inline void update(int x,int u) {
    for(;x<=d.tot;x+=lowbit(x)) C[x] += u;
}

inline int query(int x) {
    int ans = 0;
    for(;x>=1;x-=lowbit(x)) ans += C[x];
    return ans;
}

inline int find_rk(int rk) {
    int cur = 0,tot = 0;
    for(int i=(1<<20);i>=1;i>>=1) {
        cur += i;
        if(cur>d.tot||tot+C[cur]>=rk) cur -= i;
        else tot += C[cur];
    }
    return cur + 1;
}

inline void work() {
    while(count>0) {
        long long cur = d.num[ find_rk(1) ];
        if(cur + rec < line) {
            update( d.sub( cur ) , -1 );
            count --;
            ans ++;
        }
        else break;
    }
}

int main() {

    N = read(); line = read(); 
    for(int i=1;i<=N;++i) {
        
        R[i].opt = get_opt();
        R[i].num = read();
        
        if(R[i].opt=='I') d.add( R[i].num - rec );
        else if(R[i].opt=='A') rec += (long long)R[i].num;
        else if(R[i].opt=='S') rec -= (long long)R[i].num;

    }

    d.unique();

    rec = 0;
    for(int i=1;i<=N;++i) {  
        if(R[i].opt=='I'&&R[i].num>=line) {
            count++;
            update(d.sub( R[i].num - rec ),1);
        }
        else if(R[i].opt=='A') rec += (long long)R[i].num;
        else if(R[i].opt=='S') {
            rec -= (long long)R[i].num;
            work();
        }
        else if(R[i].opt=='F'){
            if(R[i].num>count) puts("-1");
            else printf("%lld\n",d.num[find_rk(count - R[i].num + 1)] + rec);
        }
    }

    printf("%d",ans);
    return 0;
}