[BZOJ 1895]Pku3580 supermemo:Splay

本文分享了一道Splay树模板题的解答过程,详细记录了作者从WA到TLE再到AC的心路历程,并总结了两次错误的原因:一是pushup函数中mn[x]初始化为inf而非v[x];二是数组容量不足,需要从1e5扩大到2e5。通过阅读本文,读者可以了解Splay树的操作细节及常见陷阱。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

点击这里查看原题

Splay模板题,我WA了一次,TLE了两次
总结一下犯的错误就是两个:

  • pushup里默认把mn[x]设为inf而非v[x]
  • 数组开小,只开了1e5,应该至少开2e5的
/*
User:Small
Language:C++
Problem No.:1895
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=3e5+5;
int n,m,a[M],rt,cnt,id[M],ch[M][2],fa[M],mn[M],v[M],siz[M],lazy[M];
bool tag[M];
queue<int> q;
void pushup(int x){
    int lson=ch[x][0],rson=ch[x][1];
    siz[x]=1;
    mn[x]=v[x];
    if(lson){
        siz[x]+=siz[lson];
        mn[x]=min(mn[x],mn[lson]);
    }
    if(rson){
        siz[x]+=siz[rson];
        mn[x]=min(mn[x],mn[rson]);
    }
}
void pushdown(int x){
    int &lson=ch[x][0],&rson=ch[x][1];
    if(lson){
        lazy[lson]+=lazy[x];
        mn[lson]+=lazy[x];
        v[lson]+=lazy[x];
    }
    if(rson){
        lazy[rson]+=lazy[x];
        mn[rson]+=lazy[x];
        v[rson]+=lazy[x];
    }
    lazy[x]=0;
    if(tag[x]){
        tag[lson]^=1;
        tag[rson]^=1;
        tag[x]^=1;
        swap(lson,rson);
    }
}
int get(int x){
    return ch[fa[x]][1]==x;
}
void rotate(int x,int &k){
    int y=fa[x],z=fa[y],side=get(x);
    if(y==k) k=x;
    else ch[z][ch[z][1]==y]=x;
    ch[y][side]=ch[x][side^1];
    fa[ch[y][side]]=y;
    fa[y]=x;
    ch[x][side^1]=y;
    fa[x]=z;
    pushup(y);
    pushup(x);
}
void splay(int x,int &k){
    while(x!=k){
        if(fa[x]!=k) rotate((get(x)==get(fa[x])?fa[x]:x),k);
        rotate(x,k);
    }
}
int findx(int x){
    int now=rt;
    while(1){
        if(tag[now]||lazy[now]) pushdown(now);
        if(siz[ch[now][0]]>=x) now=ch[now][0];
        else{
            x-=siz[ch[now][0]]+1;
            if(x<=0) return now;
            now=ch[now][1];
        }
    }
}
int spilt(int l,int r){
    int x=findx(l),y=findx(r+2);
    splay(x,rt);splay(y,ch[x][1]);
    return y;
}
void build(int l,int r,int f){
    if(l>r) return;
    int mid=l+r>>1,now=id[mid],last=id[f];
    v[now]=a[mid];
    if(l==r){
        siz[now]=1;
        mn[now]=a[mid];
    }
    else{
        build(l,mid-1,mid);
        build(mid+1,r,mid);
        pushup(now);
    }
    fa[now]=last;
    ch[last][mid>f]=now;
}
void add(int l,int r,int k){
    int x=spilt(l,r),y=ch[x][0];
    lazy[y]+=k;
    mn[y]+=k;
    v[y]+=k;
    pushup(x);
    pushup(fa[x]);
}
void ins(int x,int p){
    int y=spilt(x+1,x);
    if(!q.empty()){
        id[1]=q.front();
        q.pop();
    }
    else id[1]=++cnt;
    siz[id[1]]=1;
    v[id[1]]=mn[id[1]]=p;
    fa[id[1]]=y;
    ch[y][0]=id[1];
    pushup(y);
    pushup(fa[y]);
}
void del(int x){
    int y=spilt(x,x),z=ch[y][0];
    siz[z]=lazy[z]=tag[z]=v[z]=mn[z]=ch[z][0]=ch[z][1]=fa[z]=0;
    q.push(z);
    ch[y][0]=0;
    pushup(y);
    pushup(fa[y]);
}
int getmin(int l,int r){
    int y=spilt(l,r);
    return mn[ch[y][0]];
}
void rev(int l,int r){
    int y=spilt(l,r);
    tag[ch[y][0]]^=1;
}
void revo(int l,int r,int t){
    t%=(r-l+1);
    if(t==0) return;
    int y=spilt(r-t+1,r),x=ch[y][0];
    fa[x]=ch[y][0]=0;
    pushup(y);
    pushup(fa[y]);
    y=spilt(l,l-1);
    ch[y][0]=x;
    fa[x]=y;
    pushup(y);
    pushup(fa[y]);
}
int main(){
    freopen("data.in","r",stdin);//
    scanf("%d",&n);
    a[1]=a[n+2]=inf;
    for(int i=2;i<=n+1;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n+2;i++) id[i]=i;
    rt=(n+3)>>1,cnt=n+2;
    build(1,n+2,0);
    scanf("%d",&m);
    while(m--){
        char op[15];
        int x,y,p;
        scanf("%s%d",op,&x);
        switch(op[0]){
            case 'D':n--;del(x);break;
            case 'I':{
                scanf("%d",&p);
                n++;
                ins(x,p);
                break;
            }
            case 'A':{
                scanf("%d%d",&y,&p);
                if(x>y) swap(x,y);
                add(x,y,p);
                break;
            }
            case 'M':{
                scanf("%d",&y);
                printf("%d\n",getmin(x,y));
                break;
            }
            case 'R':{
                if(op[3]=='E'){
                    scanf("%d",&y);
                    if(x==y) continue;
                    if(x>y) swap(x,y);
                    rev(x,y);
                }
                else{
                    scanf("%d%d",&y,&p);
                    if(x>y) swap(x,y);
                    revo(x,y,p);
                }
                break;
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值