社区讨论
求助dalao们,20分splay,有注释
P1486[NOI2004] 郁闷的出纳员参与者 2已保存回复 4
讨论操作
快速查看讨论及其快照的属性,并进行相关操作。
- 当前回复
- 4 条
- 当前快照
- 1 份
- 快照标识符
- @mi6wdi5w
- 此快照首次捕获于
- 2025/11/20 11:54 4 个月前
- 此快照最后确认于
- 2025/11/20 11:54 4 个月前
CPP
#include<iostream>
#include<cstdio>
#define ls t[x].son[0]
#define rs t[x].son[1]
using namespace std;
const int maxn=1e5+10;
int n,minn,tot,root,delta,sum;
struct node
{
int val,size,fa,cnt;
int son[2];
}t[maxn];
void update(int x)
{
t[x].size=t[ls].size+t[rs].size+t[x].cnt;
}
void rotate(int x)
{
int y=t[x].fa;
int z=t[y].fa;
int k=t[y].son[1]==x;
t[z].son[t[z].son[1]==y]=x,t[x].fa=z;
t[t[x].son[k^1]].fa=y,t[y].son[k]=t[x].son[k^1];
t[x].son[k^1]=y,t[y].fa=x;
update(y),update(x);
}
void splay(int x,int to)
{
while(t[x].fa!=to)
{
int y=t[x].fa;
int z=t[y].fa;
if(z!=to)(t[z].son[1]==y)^(t[y].son[1]==x)?rotate(x):rotate(y);
rotate(x);
}
if(to==0)root=x;
}
void insert(int x)
{
int now=root,fa=0;
while(now&&t[now].val!=x)fa=now,now=t[now].son[x>t[now].val];
if(now)t[now].cnt++;
else
{
now=++tot;
if(fa)t[fa].son[x>t[fa].val]=now;
t[now].size=t[now].cnt=1;
t[now].val=x;
t[now].fa=fa;
}
splay(now,0);
}
void find(int x) //找到这个节点或距离这个节点最近的点并旋转到根
{
if(!root)return;
int now=root;
while(t[now].son[x>t[now].val]&&t[now].val!=x)now=t[now].son[x>t[now].val];
splay(now,0);
}
int find_kth(int x)//第k小
{
if(x>t[root].size)return -1;
else if(x<=0)return -1;
int now=root;
while(true)
{
int y=t[now].son[0];
if(x>t[now].cnt+t[y].size)
{
x-=t[now].cnt+t[y].size;
now=t[now].son[1];
}
else if(t[y].size>=x)now=y;
else return t[now].val;
}
}
void print(int x)
{
if(ls)print(ls);
printf("%d ",t[x].val);
if(rs)print(rs);
}
int main()
{
scanf("%d %d",&n,&minn);
insert(0x3f3f3f3f);
for(int i=1;i<=n;i++)
{
char op[10];
int k=0;
scanf("%s %d",op,&k);
if(op[0]=='I')
{
if(k-delta<minn)continue;
insert(k-delta);
sum++;
}
else if(op[0]=='A')delta+=k;
else if(op[0]=='S')
{
delta-=k;
find(minn-delta);//这里是找距离minn-delta最近的点,并旋到根
if(t[root].val>=minn-delta)// 如果根节点大于minn-delta,说明左子树都小于minn-delta,断开左子树
{
t[t[root].son[0]].fa=0;
t[root].son[0]=0;
update(root);
}
else //否则说明右子书的都大于minn-delta,就把左子树和根节点断掉即可
{
t[t[root].son[1]].fa=0;
root=t[root].son[1];
update(root);
}
}
else
{
int temp=t[root].size;
k++;
temp=find_kth(temp-k+1); //因为加入了inf,所以就是在找第k+1大。
if(temp==-1)printf("-1\n");
else printf("%d\n",temp+delta);
}
}
cout<<sum-t[root].size+1;
return 0;
}
回复
共 4 条回复,欢迎继续交流。
正在加载回复...