题意太傻不多解释= =就是维护一个档案队列,按节点val建树
思路:
从query操作(命令F)可以看出,这棵树的顺序核心在于value而不是一般的维护队列,这样的话相同value的节点显而易见地应该放在一起,我们除了s[]记录子树大小之外,额外增加一个z[]记录节点大小(对于x节点来说每有一个与其value重复的z[x]++),注意z[]不需要维护。
然后就是喜闻乐见的标记了,这道题算是比较良心= =只需要维护两个标记
add[]对当前子树进行范围修改的lazy标记
val[]单点val,需要在维护add[]的时候一起维护
然后= =就是想起来就有种自己傻的反思时间
1、Splay居然又写错了!循环时没有同步更新y和z!调了半个小时才输出出来错在这!
2、最初思路不够清晰就开始写,结果用值查找节点的时候因为想要在多个函数中用到getval这个函数两面都想满足= =结果两边都求错了【23333
3、最开始没有想到节点值相同时该怎么维护,结果只好新建节点维护成一个队列= =结局可想而知
4、查找第k大的时候想错= =如果当前节点val大于目标val直接向左走了,其实应该记录一下路径中最接近目标val的节点
5、query的时候顺序反了= =结果自己怎么看都没错,输出就是有问题…在更新了x之后想要得到关于原x的信息是自己活在梦里
于是…用了一个半小时写完了代码用了四个半小时调= =下一道Splay再这样就药丸了
#include<iostream>
#include<stdio.h>
#define lson ch[x][0]
#define rson ch[x][1]
using namespace std;
const int maxn=100005;
int n,m,k,ans,tot,root;
int ch[maxn][2],fa[maxn],add[maxn],val[maxn],s[maxn],z[maxn];
char str[5];
void link(int x,int y,int d)
{
if(y)ch[y][d]=x;
if(x)fa[x]=y;
//cout<<"link "<<x<<' '<<fa[x]<<' '<<d<<endl;
}
int ischild(int x)
{
return ch[fa[x]][1]==x;
}
void maintain(int x)
{
if(x)s[x]=s[lson]+s[rson]+z[x];
}
void pushdown(int x)
{
if(!add[x])return;
if(lson)add[lson]+=add[x],val[lson]+=add[x];
if(rson)add[rson]+=add[x],val[rson]+=add[x];
add[x]=0;
}
void rotate(int x)
{
int d=ischild(x);
int y=fa[x],z=fa[y];
if(y==root)root=x;
link(x,z,ischild(y));
link(ch[x][!d],y,d);
link(y,x,!d);
maintain(y);
}
void Splay(int x,int goal=0)
{
int y=fa[x],z=fa[y];
while(y!=goal)
{
pushdown(z);
pushdown(y);
pushdown(x);
if(z==goal)
{
rotate(x);
break;
}
if(ischild(x) ^ ischild(y))rotate(x);
else rotate(y);
rotate(x);
y=fa[x],z=fa[y];//false
}
maintain(x);
}
int getnext(int x)
{
x=ch[x][1];
while(ch[x][0])x=ch[x][0];
return x;
}
int getval(int k)
{
int x=root;
while(x)
{
pushdown(x);
if(val[x]==k)return x;//false
if(ch[x][val[x]<k])x=ch[x][val[x]<k];
else return x;
}
return x;
}
int newnode(int v)
{
int t=++tot;
s[t]=z[t]=1;
val[t]=v;
return t;
}
void addtree(int k)
{
if(!root)
{
root=newnode(k);
return;
}
int x=getval(k);
if(val[x]==k)z[x]++;
else link(newnode(k),x,val[x]<k);
Splay(x);
}
void increase(int k)
{
if(!root)return;
add[root]+=k;
val[root]+=k;
}
void decrease(int k)
{
if(!root)return;
add[root]-=k;
val[root]-=k;
int x=root,pre=0;
while(x)
{
pushdown(x);
if(val[x]==m)break;//false
if(val[x]<m)x=ch[x][1];
else
{
pre=x;
x=ch[x][0];
}
}
if(!x)x=pre;
if(x)Splay(x);
if(!x)ans+=s[root],root=0;
else ans+=s[ch[x][0]],ch[x][0]=0;
maintain(x);
}
int query(int k)
{
int x=root;
int t;
while(x)
{
pushdown(x);
t=s[ch[x][1]];
if(t>=k)x=ch[x][1];
else
if(t+z[x]>=k)return val[x];
else k-=t+z[x],x=ch[x][0];//else x=ch[x][0],k-=t+z[x];false
}
if(x)return val[x];
else return -1;
}
int que(int x,int k)
{
if(!x)return -1;
pushdown(x);
if(s[ch[x][1]]>=k)return que(ch[x][1],k);
if(s[ch[x][1]]+z[x]>=k)return val[x];
return que(ch[x][0],k-s[ch[x][1]]-z[x]);
}
int main(void)
{
//freopen("cashier2.in","r",stdin);
//freopen("cashier.ans","w",stdout);
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%s%d",str,&k);
//printf("%c %d\n",str[0],k);
if(str[0]=='I')
if(k>=m)addtree(k);
if(str[0]=='A')increase(k);
if(str[0]=='S')decrease(k);
if(str[0]=='F')printf("%d\n",query(k));
}
printf("%d\n",ans);
return 0;
}