题目大意:
题目链接:https://www.luogu.org/problem/P1486
你需要维护一下四个操作:
- I k I\ k I k:插入一个数字 k k k
- A k A\ k A k:将所有数字增加 k k k
- S k S\ k S k:将所有数字减去 k k k
- F k F\ k F k:查询第 k k k大的数字。
注意如果一个数字小于 m i n min min,那么就要把这个数字删除。
思路:
依然算是一道
T
r
e
a
p
Treap
Treap的模板题,菜到已经只会敲模板了啊。
我们发现这里的修改操作全部都是对于所有数的,所以我们不用修改所有的数字,只要记录一个
s
u
m
sum
sum表示修改的值即可。
但是注意这样的话新加入的数字应该为
k
−
s
u
m
k-sum
k−sum,因为我们定义每一个数字为
k
+
s
u
m
k+sum
k+sum,但是新加入的数字是不会被前面的修改操作影响的。所以减去
s
u
m
sum
sum之后,这个数字就是
(
k
−
s
u
m
)
+
s
u
m
=
k
(k-sum)+sum=k
(k−sum)+sum=k。
插入操作就是普通的插入操作。直接套模板就好了。
然后修改操作我们只需要把
s
u
m
sum
sum更改就行了。但是注意我们在进行
S
S
S操作时要考虑会影响到部分数字会被删除。
因为每一个数字都加上
s
u
m
sum
sum,那么对于数字
x
x
x,如果
x
+
s
u
m
<
m
i
n
x+sum<min
x+sum<min,那么
x
x
x就要被删除。也就是说,
T
r
e
a
p
Treap
Treap中所有小于
m
i
n
−
s
u
m
min-sum
min−sum的数字都要被删除。
由于修改操作很少,所以我们可以考虑暴力修改。先求出
v
a
l
=
m
i
n
−
s
u
m
val=min-sum
val=min−sum的前驱,删除该前驱后再求
v
a
l
′
=
p
r
e
(
v
a
l
)
val'=pre(val)
val′=pre(val),删除
v
a
l
′
val'
val′,以此类推,直到
v
a
l
≤
−
∞
val\leq -\infty
val≤−∞为止。
查询操作也是最基本的查询操作。但是注意查询的是第
k
k
k大,而不是第
k
k
k小。
总体来说还是很裸的,但是就是这样一道裸题都卡了我2天,不想说什么了。
代码:
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
using namespace std;
const int N=600010,Inf=2e9;
int n,minn,sum,root,tot,k,leave;
char ch;
bool flag;
struct treenode
{
int lc,rc,dat,cnt,size,val;
};
struct Treap
{
treenode t[N];
int New(int val)
{
t[++tot].val=val;
t[tot].dat=rand();
t[tot].cnt=t[tot].size=1;
return tot;
}
void update(int x)
{
t[x].size=t[t[x].lc].size+t[t[x].rc].size+t[x].cnt;
}
void build()
{
root=New(-Inf);
t[1].rc=New(Inf);
update(1);
}
void zig(int &x)
{
int y=t[x].lc;
t[x].lc=t[y].rc; t[y].rc=x; x=y;
update(t[x].rc); update(x);
}
void zag(int &x)
{
int y=t[x].rc;
t[x].rc=t[y].lc; t[y].lc=x; x=y;
update(t[x].lc); update(x);
}
void insert(int &x,int val)
{
if (!x)
{
x=New(val);
return;
}
if (t[x].val==val)
{
t[x].cnt++;
update(x);
return;
}
if (val<t[x].val)
{
insert(t[x].lc,val);
if (t[x].dat<t[t[x].lc].dat) zig(x);
}
else
{
insert(t[x].rc,val);
if (t[x].dat<t[t[x].rc].dat) zag(x);
}
update(x);
}
void del(int &x,int val)
{
if (!x) return;
if (t[x].val==val)
{
if (t[x].cnt>0)
{
leave+=t[x].cnt;
t[x].cnt=0;
//update(x);
}
if (t[x].lc || t[x].rc)
{
if (!t[x].lc || t[t[x].rc].dat>t[t[x].lc].dat)
zag(x),del(t[x].lc,val);
else
zig(x),del(t[x].rc,val);
update(x);
}
else x=0;
return;
}
if (val<t[x].val) del(t[x].lc,val);
else del(t[x].rc,val);
update(x);
}
int get_val(int x,int rank)
{
if (!x)
{
flag=0;
return Inf;
}
if (t[t[x].rc].size+1<=rank && t[t[x].rc].size+t[x].cnt>=rank)
return t[x].val;
if (rank<=t[t[x].rc].size) return get_val(t[x].rc,rank);
else return get_val(t[x].lc,rank-t[t[x].rc].size-t[x].cnt);
}
int pre(int x,int val)
{
if (!x) return -Inf;
if (t[x].val<val) return max(t[x].val,pre(t[x].rc,val));
else return pre(t[x].lc,val);
}
}Treap;
int main()
{
scanf("%d%d",&n,&minn);
srand(time(0));
Treap.build();
while (n--)
{
while (ch=getchar()) if (ch>='A'&&ch<='Z') break;
scanf("%d",&k);
if (ch=='I')
{
k-=sum;
if (k+sum>=minn) Treap.insert(root,k);
}
if (ch=='A') sum+=k;
if (ch=='S')
{
sum-=k;
int val=Treap.pre(root,minn-sum);
while (val>-Inf)
{
Treap.del(root,val);
val=Treap.pre(root,val);
}
}
if (ch=='F')
{
flag=1;
int ans=Treap.get_val(root,k+1);
if (!flag || ans<=-Inf) printf("-1\n");
else printf("%d\n",ans+sum);
}
}
printf("%d\n",leave);
return 0;
}