luogu-p1486(fhq treap)

題目描述
OIER 公司是一家大型專業化軟件公司,有着數以萬計的員工。作爲一名出納員,我的任務之一便是統計每位員工的工資。這本來是一份不錯的工作,但是令人鬱悶的是,我們的老闆反覆無常,經常調整員工的工資。如果他心情好,就可能把每位員工的工資加上一個相同的量。反之,如果心情不好,就可能把他們的工資扣除一個相同的量。我真不知道除了調工資他還做什麼其它事情。

工資的頻繁調整很讓員工反感,尤其是集體扣除工資的時候,一旦某位員工發現自己的工資已經低於了合同規定的工資下界,他就會立刻氣憤地離開公司,並且再也不會回來了。每位員工的工資下界都是統一規定的。每當一個人離開公司,我就要從電腦中把他的工資檔案刪去,同樣,每當公司招聘了一位新員工,我就得爲他新建一個工資檔案。

老闆經常到我這邊來詢問工資情況,他並不問具體某位員工的工資情況,而是問現在工資第k多的員工拿多少工資。每當這時,我就不得不對數萬個員工進行一次漫長的排序,然後告訴他答案。

好了,現在你已經對我的工作了解不少了。正如你猜的那樣,我想請你編一個工資統計程序。怎麼樣,不是很困難吧?

如果某個員工的初始工資低於最低工資標準,那麼將不計入最後的答案內

輸入格式
第一行有兩個非負整數 nn 和 \minmin。nn 表示下面有多少條命令,\minmin 表示工資下界。

接下來的 nn 行,每行表示一條命令。命令可以是以下四種之一:

I k 新建一個工資檔案,初始工資爲 kk。如果某員工的初始工資低於工資下界,他將立刻離開公司。

A k 把每位員工的工資加上 kk

S k 把每位員工的工資扣除 kk

F k 查詢第 kk 多的工資

在初始時,可以認爲公司裏一個員工也沒有。

輸出格式
輸出文件的行數爲 F 命令的條數加一。

對於每條 F 命令,你的程序要輸出一行,僅包含一個整數,爲當前工資第 kk 多的員工所拿的工資數,如果k大於目前員工的數目,則輸出 -1−1。

輸出文件的最後一行包含一個整數,爲離開公司的員工的總數。

輸入輸出樣例
輸入

9 10
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2

輸出

10
20
-1
2

說明/提示
【數據範圍】

I 命令的條數不超過 10510^5
A 和 S 命令的總條數不超過 100;
F 命令的條數不超過 10510^5
每次工資調整的調整量不超過 10310^3
新員工的工資不超過 10510^5

這道題是一道標準的平衡樹板子題,我們需要的操作是刪除一些點,加入一些點和求排名,這個題很容易想到的一點就是我們可以用一個變量來存從開始到現在工資變化了多少,然後我們在將一個員工加入檔案時,我們可以將他的工資轉換爲沒有變化工資之前的工資,然後我們在求第k大時把工資變化總量加上就可以啦。而這裏刪除員工時,刪除的是所有工資小於最低值的員工,這個時候我們也將最小工資也轉換爲相對於工資沒有變化時的工資,然後用fhq treap操作分裂一下,把小的子樹刪去就可以啦。
代碼:

#pragma GCC optimize(2)
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
std::mt19937 rnd(233);
struct treap
{
    int size, val, l, r, key;
} fhq[maxn];
int cnt, root, tmp = 0, ans;
inline int newnode(int val)
{
    fhq[++cnt] = treap{1, val, 0, 0, rnd()};
    return cnt;
}
inline void update(int now)
{
    fhq[now].size = fhq[fhq[now].l].size + fhq[fhq[now].r].size + 1;
}
inline void split(int now,int val,int &x,int &y)
{
    if(!now){
        x = y = 0;
        return;
    }
    if(fhq[now].val<=val){
        x = now;
        split(fhq[now].r, val, fhq[now].r, y);
    }
    else{
        y = now;
        split(fhq[now].l, val, x, fhq[now].l);
    }
    update(now);
}
inline int merge(int x,int y)
{
    if(!x||!y)
        return x + y;
    if(fhq[x].key>fhq[y].key){
        fhq[x].r = merge(fhq[x].r, y);
        update(x);
        return x;
    }
    else{
        fhq[y].l = merge(x, fhq[y].l);
        update(y);
        return y;
    }
}
int x, y, z;
inline void insert(int val)
{
    split(root, val, x, y);
    root = merge(merge(x, newnode(val)), y);
}
inline void del(int val)
{
    split(root, val, x, z);
    ans += fhq[x].size;
    root = z;
}
inline void getnum(int k)
{
    int now = root;
    while(now){
        if(fhq[fhq[now].r].size+1==k)
            break;
        if(fhq[fhq[now].r].size>=k){
            now = fhq[now].r;
        }
        else{
            k -= (fhq[fhq[now].r].size + 1);
            now = fhq[now].l;
        }
    }
    if(!now){
        printf("-1\n");
        return;
    }
    printf("%d\n", fhq[now].val + tmp);
}
inline void read(int &val)
{
    val = 0;
    int f = 1;
    char c = getchar();
    while(c<'0' || c>'9'){
        if(c=='-')
            f = -1;
        c = getchar();
    }
    while(c>='0' && c<='9'){
        val = val * 10 + c - '0';
        c = getchar();
    }
    val *= f;
}
char s[6];
int main()
{
    int n, m;
    read(n), read(m);
    while(n--){
        scanf("%s", s);
        int num;
        read(num);
        if(s[0]=='I'){
            if(num<m)continue;
			num -= tmp;
            //cout<<num<<endl;
            insert(num);
        }
        else if(s[0]=='A'){
            tmp += num;
            //del(m - tmp - 1);
        }
        else if(s[0]=='S'){
            tmp -= num;
            del(m - 1 - tmp);
        }
        else{
            getnum(num);
        }
    }
    printf("%d\n",ans);
}

總結一下遇到的鍋,在判斷時需要加一個判斷,此時的工資是否大於等於最低工資(PS:最開始我想到了的,想着把bug找出來就加上去,然後到最後WA了纔想到加上去[霧])。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章