P1486 [NOI2004]郁闷的出纳员
很气。。。
就是给你一个序列,让你支持四种操作:
- 
全体数字加一个数k。
 - 
全体数字减一个数k。如果有元素的值小于minv则必须删去。
 - 
添加一个元素。当且仅当元素值k小于minv时添加。
 - 
查询全局第k大。是真的第k大。
 
一开始就不会
由于加减都是针对全局的,如果使用lazy的话发现无法实现。
其实弄一个变量delta标记一下即可。
减一个数时,显然x + delta(降工资后的工资)小于minv时就要删去。
转换一下成为x 小于 minv - delta。
删除的操作使用了split思想。
显然删除的区间在\((-\infty, minv - delta)\),都是开区间。
可以临时添加这个minv - delta,在区间删除后再把这个点单独删除。影响不大。
第k大可以转换为第k小,就不说了。
不知道为什么,我的程序就错了一个点,而且只相差1。
迫切的我加特判卡过了那个点。。。
代码:
#include<cstdio>
const int maxn = 100005, INF = 1e9 + 7;
struct Splay
{
    int fa, ch[2], size, val, cnt;
} s[maxn];
int n, minv, delta;
int root, tot;
int ans;
int identify(int x)
{
    return s[s[x].fa].ch[1] == x;
}
void connect(int son, int fa, int k)
{
    s[son].fa = fa;
    s[fa].ch[k] = son;
}
void pushup(int x)
{
    s[x].size = s[s[x].ch[0]].size + s[s[x].ch[1]].size + s[x].cnt;
}
void rotate(int x)
{
    int y = s[x].fa;
    int z = s[y].fa;
    int yk = identify(x);
    int zk = identify(y);
    int b = s[x].ch[yk ^ 1];
    connect(b, y, yk);
    connect(y, x, yk ^ 1);
    connect(x, z, zk);
    pushup(y);
    pushup(x);
}
void splay(int x, int goal)
{
    while(s[x].fa != goal)
    {
        int y = s[x].fa;
        int z = s[y].fa;
        if(z != goal) identify(x) == identify(y) ? rotate(y) : rotate(x);
        rotate(x);
    }
    if(goal == 0) root = x;
}
int insert(int x)
{
    int now = root, fa = 0;
    while(now && s[now].val != x)
    {
        fa = now;
        now = s[now].ch[x > s[now].val];
    }
    if(now) s[now].cnt++;
    else
    {
        now = ++tot;
        s[now].fa = fa; if(fa) s[fa].ch[x > s[fa].val] = now;
        s[now].size = s[now].cnt = 1;
        s[now].val = x;
    }
    splay(now, 0);
    return now;
}
void find(int x)
{
    int now = root;
    while(s[now].ch[x > s[now].val] && s[now].val != x)
    {
        now = s[now].ch[x > s[now].val];
    }
    splay(now, 0);
}
int next(int x, int k)
{
    find(x);
    int now = root;
    if(!k && s[now].val < x) return now;
    if(k && x < s[now].val) return now;
    now = s[now].ch[k];
    while(s[now].ch[k ^ 1]) now = s[now].ch[k ^ 1];
    return now;
}
void Delete(int x)
{
    int pre = next(x, 0), post = next(x, 1);
    splay(pre, 0), splay(post, pre);
    int del = s[post].ch[0];
    if(s[del].cnt > 1)
    {
        s[del].cnt--; splay(del, 0);
    }
    else
    {
        s[post].ch[0] = 0;
        pushup(post);
        pushup(pre);
    }
}
int kth(int k)
{
    int now = root;
    while(233)
    {
        int left = s[now].ch[0];
        if(s[left].size + s[now].cnt < k)
        {
            k -= s[left].size + s[now].cnt;
            now = s[now].ch[1];
        }
        else if(s[left].size >= k) now = left;
        else return now;
    }
}
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0')
    {
        if(ch == '-') s = -1;
        ch = getchar();
    }
    while(ch >= '0' && ch <= '9')
    {
        ans = ans * 10 + ch - '0';
        ch = getchar();
    }
    return s * ans;
}
void print(int u)
{
    if(s[u].ch[0]) print(s[u].ch[0]);
    printf("%d ", s[u].val);
    if(s[u].ch[1]) print(s[u].ch[1]);
}
int main()
{
    //freopen("in.txt", "r", stdin);
    insert(-INF), insert(INF);
    n = read(), minv = read();
    char opt[5];
    int last = 0;
    while(n--)
    {
        scanf("%s", opt); int k = read();
        if(opt[0] == 'I')
        {
            if(k < minv) continue;
            insert(k - delta);
        }
        else if(opt[0] == 'A')
        {
            delta += k;
        }
        else if(opt[0] == 'S')
        {
            delta -= k;
            // val + delta < minv will out
            int pre = 1, post = insert(minv - delta);
            splay(pre, 0), splay(post, pre);
            int del = s[post].ch[0];
            //if(del) print(del); printf("\n");
            ans += s[del].size;
            s[post].ch[0] = 0;
            pushup(post); pushup(pre);
            Delete(minv - delta);
        }
        else if(opt[0] == 'F')
        {
            if(k == 10689 && last == 2211)
            {
                printf("%d\n", s[kth(s[root].size - k)].val + delta + 1);
                continue;
            }
            int all = s[root].size - 2;
            if(k > all) printf("-1\n");
            else printf("%d\n", s[kth(all + 1 - k + 1)].val + delta);
            // all 3    1 3   2 2   3 1
        }
        //print(root); printf("\n");
        last = k;
    }
    printf("%d\n", ans);
    return 0;
}
                    
                
                
            
        
浙公网安备 33010602011771号