题目链接:P1486 [NOI2004]郁闷的出纳员
题意:中文题意
一、权值线段树
注意到加值与减值都是对整体加减,故可以记录修改量
c
h
a
n
g
e
change
change,表示所有的
+
k
i
+k_i
+ki与
−
k
i
-k_i
−ki,那么插值可以看做插一个权值为
x
−
c
h
a
n
g
e
x-change
x−change的点,工资下降可看做是对值域区间
[
0
,
m
i
n
n
−
c
h
a
n
g
e
−
1
]
[0,minn-change-1]
[0,minn−change−1]清零,第k大可看做是查询值域区间
[
m
i
n
n
−
c
h
a
n
g
e
,
+
o
o
]
[minn-change,+oo]
[minn−change,+oo]内的第k大。
当然为了防止数字越到负数上,可以对维护的权值先全部加一个超大值。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4e5+7;
ll num[maxn<<2|1];
bool vis[maxn<<2|1];
const int cc=2e5;
void pushup(int k){ num[k]=num[k<<1]+num[k<<1|1]; }
void pushdown(int k){
if(vis[k]){
vis[k<<1]=vis[k<<1|1]=vis[k];
num[k<<1]=num[k<<1|1]=0;
vis[k]=0;
}
}
void insert(int l,int r,int k,int id){
if(l==r){
++num[k];
return ;
}
int mid=l+r>>1;
pushdown(k);
if(id<=mid) insert(l,mid,k<<1,id);
else insert(mid+1,r,k<<1|1,id);
pushup(k);
}
int del(int l,int r,int k,int L,int R){
int res=0;
if(l>=L&&r<=R){
vis[k]=1;
res=num[k];
num[k]=0;
return res;
}
int mid=l+r>>1;
pushdown(k);
if(L<=mid) res+=del(l,mid,k<<1,L,R);
if(R>mid) res+=del(mid+1,r,k<<1|1,L,R);
pushup(k);
return res;
}
int query(int l,int r,int k,int L,int R){
if(l>=L&&r<=R) return num[k];
int mid=l+r>>1; pushdown(k);
int res=0;
if(L<=mid) res+=query(l,mid,k<<1,L,R);
if(R>mid) res+=query(mid+1,r,k<<1|1,L,R);
return res;
}
int kth(int l,int r,int k,int id,int val){
if(l==r){
if(num[k]<val) return -1;
return l;
}
pushdown(k);
int mid=l+r>>1;
if(id>mid) return kth(mid+1,r,k<<1|1,id,val);
else{
int vv=query(mid+1,r,k<<1|1,mid+1,r);
if(vv>=val) return kth(mid+1,r,k<<1|1,id,val);
return kth(l,mid,k<<1,id,val-vv);
}
}
char s[9];
#define debug(x) cout<<(#x)<<" : "<<(x)
int main(){
int q,mm=0,x;
ll minn;
ll change=0;
scanf("%d%lld",&q,&minn);
while(q--){
scanf("%s%d",s,&x);
if(s[0]=='I'){
if(x<minn) continue;
insert(0,maxn-1,1,x+cc-change);
}
else if(s[0]=='A'){
change+=x;
}
else if(s[0]=='S'){
change-=x;
//debug(minn-change+cc-1)<<endl;
if(minn-change+cc-1>=0) mm+=del(0,maxn-1,1,0,minn-change+cc-1);
}
else{
int res=kth(0,maxn-1,1,max(minn-change+cc,0LL),x);
if(res==-1) printf("-1\n");
else printf("%d\n",res+change-cc);
}
}
printf("%d\n",mm);
return 0;
}
二、splay
就直接维护splay,支持插入,删除,打懒标记。
暂时还没学完splay,是个口胡王者。