splay模板题,都快把我做忧郁了。
由于自己调两个坑点。
1.删除时及时updata
2.Kth 考虑k满足该点的条件即r->ch[1]->size+1<=k && r->ch[1]->size+r->num>=k
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
struct SplayNode
{
SplayNode *fa,*ch[];
SplayNode();
int data,size,num;
int chr() {return this==fa->ch[];}
void updata() { size=ch[]->size+ch[]->size+num;}
}*null;
SplayNode::SplayNode() {fa=ch[]=ch[]=null; num=; size=;}
int n,minn;
inline int read() {int ans=; char c; while ((c=getchar())==' ' || c=='\r' || c=='\n'); ans=c-''; while (isdigit(c=getchar())) ans=ans*+c-''; return ans;}
namespace Splay
{
SplayNode *Root;
void MakeTree()
{
null=new SplayNode;
*null=SplayNode();
Root=null;
}
void rotate(SplayNode *x)
{
SplayNode *r=x->fa;
if (x==null || r==null) return;
int t=x->chr();
r->ch[t]=x->ch[t^];
r->ch[t]->fa=r;
if (r->fa==null) Root=x;
else r->fa->ch[r->chr()]=x;
x->fa=r->fa;
x->ch[t^]=r;
r->fa=x;
r->updata();
x->updata();
}
void splay(SplayNode *x,SplayNode *y)
{
for (;x->fa!=y;rotate(x))
if (x->fa->fa!=y)
if (x->chr()==x->fa->chr()) rotate(x->fa);
else rotate(x);
}
void insert(int v)
{
SplayNode *r=Root;
if (Root==null)
{
Root=new SplayNode;
Root->data=v;
Root->updata();
return;
}
if (Root->data==v)
{
Root->num++;
Root->updata();
return;
}
while (r->ch[r->data<v]!=null)
{
r=r->ch[r->data<v];
if (r->data==v)
{
r->num++;
splay(r,null);
return;
}
}
r->ch[r->data<v]=new SplayNode;
r->ch[r->data<v]->data=v;
r->ch[r->data<v]->fa=r;
splay(r->ch[r->data<v],null);
}
void pre(SplayNode *x,int v,SplayNode *&ans)
{
if (x==null) return;
else if (x->data<v)
{
if (ans->data<x->data || ans==null) ans=x;
pre(x->ch[],v,ans);
}else pre(x->ch[],v,ans);
}
void suc(SplayNode *x,int v,SplayNode *&ans)
{
if (x==null) return;
else if (x->data>v)
{
if (ans->data>x->data || ans==null) ans=x;
suc(x->ch[],v,ans);
}else suc(x->ch[],v,ans);
}
void del(int v)
{
SplayNode *q=null; pre(Root,v,q);
SplayNode *p=null; suc(Root,v,p);
if (q==null && p==null)
{
if (Root->num==) Root=null;
else Root->num--,Root->updata();
return;
}
if (q==null)
{
splay(p,null);
if (p->ch[]->num==) p->ch[]=null,p->updata();
else p->ch[]->num--,splay(p->ch[],null);
return;
}
if (p==null)
{
splay(q,null);
if (q->ch[]->num==) p->ch[]=null,p->updata();
else p->ch[]->num--,splay(p->ch[],null);
return;
}
splay(q,null);
splay(p,q);
if (p->ch[]->num==) p->ch[]=null,p->updata();
else p->ch[]->num--,splay(p->ch[],null);
return;
}
SplayNode *Kth(int k)
{
SplayNode *r=Root;
while (r!=null)
{
if (k<=r->ch[]->size) r=r->ch[];
else if (r->ch[]->size+<=k && r->ch[]->size+r->num>=k) return r;
else
{
k-=r->ch[]->size+r->num;
r=r->ch[];
}
}
return r;
}
SplayNode *find(int v)
{
SplayNode *r=Root;
while (r!=null)
{
if (r->data==v)
{
splay(r,null);
return r;
}
r=r->ch[r->data<v];
}
return null;
}
}
int main()
{
//freopen("1503.out","w",stdout);
int ans=,dell=,ans1=;
Splay::MakeTree();
n=read(); minn=read();
while (n--)
{
char s[];
int x;
scanf("%s",s); x=read();
if (s[]=='I') if (x>=minn) Splay::insert(x-dell),ans++;
if (s[]=='A') dell+=x;
if (s[]=='S')
{
dell-=x;
Splay::insert(minn-dell);
SplayNode *r=Splay::find(minn-dell);
// Splay::splay(r,null);
if (r->ch[]!=null) ans1+=r->ch[]->size,ans-=r->ch[]->size;
while (r->ch[]!=null)
{
Splay::del(r->ch[]->data);
Splay::splay(r,null);
}
Splay::del(minn-dell);
}
if (s[]=='F')
if (x>ans) puts("-1");
else
printf("%d\n",Splay::Kth(x)->data+dell);
}
printf("%d\n",ans1);
return ;
}
Description
OIER公司是一家大型专业化软件公司,有着数以万计的员工。作为一名出纳员,我的任务之一便是统计每位员工的工资。这本来是一份不错的工作,但是令人郁闷的是,我们的老板反复无常,经常调整员工的工资。如果他心情好,就可能把每位员工的工资加上一个相同的量。反之,如果心情不好,就可能把他们的工资扣除一个相同的量。我真不知道除了调工资他还做什么其它事情。工资的频繁调整很让员工反感,尤其是集体扣除工资的时候,一旦某位员工发现自己的工资已经低于了合同规定的工资下界,他就会立刻气愤地离开公司,并且再也不会回来了。每位员工的工资下界都是统一规定的。每当一个人离开公司,我就要从电脑中把他的工资档案删去,同样,每当公司招聘了一位新员工,我就得为他新建一个工资档案。老板经常到我这边来询问工资情况,他并不问具体某位员工的工资情况,而是问现在工资第k多的员工拿多少工资。每当这时,我就不得不对数万个员工进行一次漫长的排序,然后告诉他答案。好了,现在你已经对我的工作了解不少了。正如你猜的那样,我想请你编一个工资统计程序。怎么样,不是很困难吧?
Input
Output
输出文件的行数为F命令的条数加一。对于每条F命令,你的程序要输出一行,仅包含一个整数,为当前工资第k多的员工所拿的工资数,如果k大于目前员工的数目,则输出-1。输出文件的最后一行包含一个整数,为离开公司的员工的总数。
Sample Input
I 60
I 70
S 50
F 2
I 30
S 15
A 5
F 1
F 2
Sample Output
20
-1
2
HINT
I命令的条数不超过100000 A命令和S命令的总条数不超过100 F命令的条数不超过100000 每次工资调整的调整量不超过1000 新员工的工资不超过100000