【权值分块】bzoj1503 [NOI2004]郁闷的出纳员

权值分块,离散化非常蛋疼,只能离散化搞……

需要支持操作:删除<=某个值得所有权值==打标记 O(sqrt(n))

码长和我的平衡树差不多……速度快3倍左右。

  1 #include<cstdio>
  2 #include<cmath>
  3 #include<algorithm>
  4 #include<cstring>
  5 using namespace std;
  6 #define N 201001
  7 struct Point{int v,p;}tmp[N];
  8 bool operator < (const Point &a,const Point &b){return a.v<b.v;}
  9 int n,m,Infu,a[N],c[N],leave,
 10 en/*插入的权值数*/,en2/*离散化之后的权值种类数*/,ma[N];
 11 char op[N];
 12 int num[N],l[460],CH[12],r[460],Num,sumv[460],sum,sz,b[N],all;
 13 bool delta[N];
 14 inline void R(int &x){
 15     char c=0;int f=1;
 16     for(;c<‘0‘||c>‘9‘;c=getchar())if(c==‘-‘)f=-1;
 17     for(x=0;c>=‘0‘&&c<=‘9‘;c=getchar())(x*=10)+=(c-‘0‘);
 18     x*=f;
 19 }
 20 inline void P(int x)
 21 {
 22     if(!x){putchar(‘0‘);puts("");return;}
 23     if(x<0){putchar(‘-‘);x=-x;}Num=0;
 24     while(x>0)CH[++Num]=x%10,x/=10;
 25     while(Num)putchar(CH[Num--]+48);puts("");
 26 }
 27 void makeblock()
 28 {
 29     sz=sqrt(en2); if(!sz) sz=1;
 30     for(sum=1;sum*sz<en2;sum++)
 31       {
 32           l[sum]=r[sum-1]+1;
 33           r[sum]=sum*sz;
 34           for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
 35       }
 36     l[sum]=r[sum-1]+1;
 37     r[sum]=en2;
 38     for(int i=l[sum];i<=r[sum];i++) num[i]=sum;
 39 }
 40 void pushdown(const int &p)
 41 {
 42     if(delta[p])
 43       {
 44           for(int i=l[p];i<=r[p];i++) b[i]=0;
 45           delta[p]=0;
 46       }
 47 }
 48 inline void Insert(const int &x){pushdown(num[x]); b[x]++; sumv[num[x]]++; all++;}
 49 inline void Delete(const int &v)//删除小于等于v的所有权值
 50 {
 51     int used=all; pushdown(num[v]);
 52     for(int i=v;i>=l[num[v]];i--)
 53       {
 54           sumv[num[i]]-=b[i];
 55           all-=b[i];
 56           b[i]=0;
 57       }
 58     for(int i=num[v]-1;i>=1;i--) if(sumv[i])
 59       {
 60           delta[i]=1;
 61           all-=sumv[i];
 62           sumv[i]=0;
 63       } leave+=(used-all);
 64 }
 65 inline int Kth(const int &x)
 66 {
 67     int cnt=0;
 68     for(int i=sum;;i--)
 69       {
 70         cnt+=sumv[i];
 71         if(cnt>=x)
 72           {
 73             cnt-=sumv[i];
 74             for(int j=r[i];;j--)
 75             {cnt+=b[j]; if(cnt>=x) return j;}
 76           }
 77       }
 78 }
 79 int main()
 80 {
 81     R(n); R(m);
 82     for(int i=1;i<=n;i++)
 83       {
 84           op[i]=getchar(); R(a[i]);
 85           if(op[i]==‘I‘)
 86             {
 87                 tmp[++en].v=a[i]-Infu;//为新员工消除之前工资变化的影响
 88                 tmp[en].p=en;
 89             }
 90           else if(op[i]==‘A‘) Infu+=a[i];
 91           else if(op[i]==‘S‘)
 92           {
 93               Infu-=a[i];
 94               tmp[++en].v=m-Infu-1;//每次删除<=m-Infu-1的权值
 95               tmp[en].p=en;
 96           }
 97       }
 98     sort(tmp+1,tmp+en+1);
 99     ma[c[tmp[1].p]=++en2]=tmp[1].v;
100     for(int i=2;i<=en;i++)
101       {
102           if(tmp[i].v!=tmp[i-1].v) en2++;
103           ma[c[tmp[i].p]=en2]=tmp[i].v;
104       } Infu=en=0; makeblock();
105     for(int i=1;i<=n;i++)
106       {
107           if(op[i]==‘I‘) {en++; if(a[i]>=m) Insert(c[en]);}
108           else if(op[i]==‘A‘) Infu+=a[i];
109           else if(op[i]==‘S‘)
110           {
111             Infu-=a[i];
112             Delete(c[++en]);
113           }
114           else
115             {
116                 if(a[i]>all) puts("-1");
117                 else P(ma[Kth(a[i])]+Infu);
118             }
119       } P(leave);
120     return 0;
121 }
时间: 2024-10-05 09:25:11

【权值分块】bzoj1503 [NOI2004]郁闷的出纳员的相关文章

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

[BZOJ1503] [NOI2004] 郁闷的出纳员 (treap)

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

BZOJ1503 [NOI2004]郁闷的出纳员

AC通道:http://www.lydsy.com/JudgeOnline/problem.php?id=1503 [我的感受] 这题郁闷了很久,因为discuss里讨论的问题和我都不是一个问题... discuss里的当然是一大坑点啦,就是初始工资挂了的不算在最后踢出的人数中. 不过这个我倒是刚开始就这么打的...不过我一直超时啊超时啊... 终于要来了数据...额,原来是平衡树的性质都没怎么用...根本没转几次啊,然后数据就特意卡了这个,连续添加递增工资的人[变成了链] 那我就随机转一转好了

bzoj1503: [NOI2004]郁闷的出纳员 fhqtreap版

这道题写法和之前差不多 但是fhqtreap在加点的时候为了同时维护大根堆以及二叉排序树的性质所以插入时也要注意分裂 fhqteap需要判断指针是否为空 不然就会re 这个我调了很久 #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int M=150000; int read(){ int ans=0,f=1,c=getchar(); while(c<

BZOJ1503 NOI2004 郁闷的出纳员 平衡树

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

bzoj 1503: [NOI2004]郁闷的出纳员 -- 权值线段树

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

1503: [NOI2004]郁闷的出纳员 Treap

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

BZOJ 题目1503: [NOI2004]郁闷的出纳员(SBT+延迟操作)

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