社区讨论

求助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 条回复,欢迎继续交流。

正在加载回复...