bzoj1503 郁闷的出纳员(平衡树,思维)

题目大意:

现在有n个操作和一个最低限度m

\(I\)命令\(I\ k\)新建一个工资档案,初始工资为k。

\(A\)命令$A k $把每位员工的工资加上k

\(S\)命令$S k $把每位员工的工资扣除k

\(F\)命令$ F k\(查询第k多的工资 (如果当前的员工总数不够k,就输出\)-1$)

其中\(n \le 100000\)

最后还要输出最终离开了多少个员工

需要注意的是 ,如果某员工的初始工资低于工资下界,他将立刻离开公司!!!!

一看这个题,就感觉是个\(splay\)了

不过emmmm 这个整体加和整体减应该怎么弄呢

我们考虑维护一个整体的变化值\(tmp\)

那么对于splay中的每个元素,它的实际权值就是\(x+tmp\)

这么来说

对于\(I\)操作,如果它的权值\(>\)m,则\(insert(x-tmp)\)

对于\(A\)操作,直接\(tmp+=x\)

对于\(S\)操作,我们让\(tmp-=x\),并且判断有没有需要退出的点(就是直接将\(-inf\)转到\(root\),然后把\(min1-tmp-1\)的后继转到root的右儿子,删掉左儿子)这样做的原因是避免哨兵被删掉

对于\(F\)操作,那就直接返回第k大,然后\(+tmp\)就可以

代码还是有很多细节的,比如要维护当前平衡树中有几个元素,事先加入哨兵之类的,直接看代码吧

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<vector>

using namespace std;

inline int read()
{
   int x=0,f=1;char ch=getchar();
   while (!isdigit(ch)){if (ch==‘-‘) f=-1;ch=getchar();}
   while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-‘0‘;ch=getchar();}
   return x*f;
}

const int maxn = 1e6+1e2;

int ch[maxn][4];
int val[maxn],sz[maxn],size;
int fa[maxn];
int cnt[maxn];
int n,m,ymh,root,min1;
int tot;
int num=0;
int ans;

int son(int x)
{
    if (x==ch[fa[x]][0]) return 0;
    else return 1;
}
void update(int x)
{
    sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
}

void rotate(int x)
{
    int y=fa[x],z=fa[y];
    int b=son(x),c=son(y);
    ch[z][c]=x;
    fa[x]=z;
    ch[y][b]=ch[x][!b];
    fa[ch[x][!b]]=y;
    ch[x][!b]=y;
    fa[y]=x;
    update(y);
    update(x);
}

void splay(int x,int p)
{
    while (fa[x]!=p)
    {
        int y=fa[x],z=fa[y];
        if (z==p) rotate(x);
        else
        {
            if (son(x)==son(y))
            {
                rotate(y);
                rotate(x);
            }
            else
            {
                rotate(x);
                rotate(x);
            }
        }
    }
    if (fa[x]==0) root=x;
}

int find_qq(int x)
{
    int now = root,num=0;
    while (now)
    {
        if (val[now]<x)
        {
            num=now;
            now=ch[now][1];
        }
        else now=ch[now][0];
    }
    return num;
}

int find_hj(int x)
{
    int now = root,num=0;
    while (now)
    {
        if (val[now]>x)
        {
            num=now;
            now=ch[now][0];
        }
        else now=ch[now][1];
    }
    return num;
}

void insert(int x)
{
    tot++;
    int qq = find_qq(x);
    int hj = find_hj(x);
    splay(qq,0);
    splay(hj,qq);
    int y = ch[hj][0];
    if (cnt[y])
    {
        cnt[y]++;
        update(y);
    }
    else
    {
        ++size;
        ch[hj][0]=size;
        fa[size]=hj;
        val[size]=x;
        cnt[size]=1;
        sz[size]=1;
        //cout<<"gg11"<<endl;
        update(size);
    }
}

void delet(int x)
{
    --tot;
    int qq = find_qq(x);
    int hj = find_hj(x);
    splay(qq,0);
    splay(hj,qq);
    int y = ch[hj][0];
    if (cnt[y]>1)
    {
        cnt[y]--;
        update(y);
    }
    else
    {
        cnt[y]=0;
        fa[y]=0;
        ch[hj][0]=0;
        sz[y]=0;
        val[y]=0;
    }
}

int kth(int x)
{
    int now = root;
    while (1)
    {
        if (x<=sz[ch[now][0]]) now=ch[now][0];
        else{
            if (x<=sz[ch[now][0]]+cnt[now]) return val[now];
            x-=sz[ch[now][0]]+cnt[now];
            now=ch[now][1];
          }
    }
}

int add;

int main()
{
  size=2;
  val[1]=2e9;
  val[2]=-2e9;
  fa[2]=1;
  ch[1][0]=2;
  root=1;
  scanf("%d%d",&n,&min1);
  for (int i=1;i<=n;i++)
  {
    char s[10];
    int x;
    scanf("%s",s+1);
    //cout<<size<<endl;
    x=read();
    //cout<<x<<endl;
    if (s[1]==‘A‘)
    {
        ymh+=x;
      }
    if (s[1]==‘S‘)
    {
        ymh-=x;
        int hj = find_hj(min1-ymh-1);
        splay(2,0);
        splay(hj,2);
        int pos = ch[hj][0];
        ans+=sz[pos];
        tot-=sz[pos];
        fa[pos]=0;
        ch[hj][0]=0;
        sz[pos]=0;
        cnt[pos]=0;
        /*if (tot==0)
        {
        size=2;
            val[1]=2e9;
            val[2]=-2e9;
            fa[2]=1;
            ch[1][0]=2;
            root=1;
        }*/
        //cout<<ans;
    }
    if (s[1]==‘I‘)
    {
        if (x<min1) continue;
        //cout<<"gg"<<endl;
        insert(x-ymh);
    }
    if (s[1]==‘F‘)
    {
        //cout<<tot<<endl;
        if (x>tot)
          printf("-1\n");
        else
          printf("%d\n",kth(tot-x+1)+ymh);
    }
    //cout<<tot<<endl;
  }
  cout<<ans;
  return 0;
}

原文地址:https://www.cnblogs.com/yimmortal/p/10160798.html

时间: 2024-10-10 00:03:44

bzoj1503 郁闷的出纳员(平衡树,思维)的相关文章

bzoj 1503: [NOI2004]郁闷的出纳员 平衡树

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 12250  Solved: 4372[Submit][Status][Discuss] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之

[NOI2004][BZOJ1503] 郁闷的出纳员

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 7749  Solved: 2725[Submit][Status][Discuss] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,

BZOJ1503 NOI2004 郁闷的出纳员 平衡树

题意:开始时给定一个空的数列,要求维护:1.加入一个数  2.数列中所有元素+k  3.数列中所有元素-k  4.查询数列中的第k大.其中对于任意时刻,如果有一个元素<Min,则删除该元素. 题解:平衡树裸题……话说当年还打算把Splay Treap SBT都学一下,结果现在只会Splay了QAQ #include <cstdio> #include <cstring> #include <cstdlib> #include <climits> #in

bzoj1503 郁闷的出纳员

Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可能把他们的工资扣除一个相同的量.我真不知道除了调工资他还做什么其它事情.工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司

【NOI2004】【BZOJ1503】【重制版本(可过BZOJ+加速)】郁闷的出纳员

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 6524  Solved: 2277 [Submit][Status] Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,

bzoj1503 [NOI2004]郁闷的出纳员(名次树+懒惰标记)

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MBSubmit: 8705  Solved: 3027[Submit][Status][Discuss] Description OIER 公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是, 我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反

[BZOJ1503][NOI2004]郁闷的出纳员 无旋Treap

1503: [NOI2004]郁闷的出纳员 Time Limit: 5 Sec  Memory Limit: 64 MB Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可能把他们的工资扣除一个相同的量.我真不知道除了调工资他还做什么其它事情.工资的频繁调

[BZOJ 1503] [NOI2004] 郁闷的出纳员

1503: [NOI2004] 郁闷的出纳员 Time Limit: 5 SecMemory Limit: 64 MB Description OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可能把他们的工资扣除一个相同的量.我真不知道除了调工资他还做什么其它事情.工资的频繁调整

NOI2004 郁闷的出纳员 Splay

郁闷的出纳员 [问题描述] OIER公司是一家大型专业化软件公司,有着数以万计的员工.作为一名出纳员,我的任务之一便是统计每位员工的工资.这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资.如果他心情好,就可能把每位员工的工资加上一个相同的量.反之,如果心情不好,就可能把他们的工资扣除一个相同的量.我真不知道除了调工资他还做什么其它事情. 工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离