这个题会卡替罪羊吗

P6136 【模板】普通平衡树(数据加强版)

cbdsopa @ 2020-11-05 20:00:09

MLE了

开不了那么多数组

而且数据范围给的有问题吧

#include<bits/stdc++.h>
using namespace std;
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout);
#define MAXN 1500010
int tot,w[MAXN],lc[MAXN],rc[MAXN],cnt[MAXN],size[MAXN],delt[MAXN],rt,fd[MAXN];
double alpha=0.7;
/*
tot 树中元素数量
rt 根节点,rt=0时表示树空
w 点权
lc rc 左右子树
cnt 数值出现个数
size 以本节点为根的子树大小
fd 被删除的点
delt 被删除节点子树大小
alpha 常数,重建比例数 
*/
int n,m,ans;
void calc(int k)//计算以k为根的子树大小 
{
    size[k]=size[lc[k]]+size[rc[k]]+1;
    delt[k]=delt[lc[k]]+delt[rc[k]]+cnt[k];
}
bool canrbu(int k)//判断当前节点是否需要重建 
{
    return cnt[k]&&(alpha*size[k]<=(double)max(size[lc[k]],size[rc[k]]))||((double)delt[k]<=alpha*size[k]); 
} 
void rbu_flatten(int& x,int k)//中序遍历展开k的子树 
{
    if(!k) return;
    rbu_flatten(x,lc[k]);
    if(cnt[k]) fd[x++]=k;
    rbu_flatten(x,rc[k]);
}
int rbu_build(int l,int r)//二分将fd的区间[l,r)重建成树 
{
    int mid=(l+r)>>1;
    if(l>=r) return 0;
    lc[fd[mid]]=rbu_build(l,mid);
    rc[fd[mid]]=rbu_build(mid+1,r);
    calc(fd[mid]);
    return fd[mid];
}
void rbu(int& k)//重建节点k的主函数 
{
    int x=0;
    rbu_flatten(x,k);
    k=rbu_build(0,x);
} 
void insert(int& x,int k)//将值为k的点加入根为x的点中 
{
    if(!x)
    {
        x=++tot;
        if(!rt) rt=1;
        w[x]=k;
        lc[x]=rc[x]=0;
        cnt[x]=size[x]=delt[x]=1;
    }
    else 
    {
        if(w[x]==k) ++cnt[x];
        else if(w[x]<k) insert(rc[x],k);
        else insert(lc[x],k);
        calc(x);
        if(canrbu(x)) rbu(x);
    }
}
void del(int& x,int k)//从x为根的子树中移除一个值为k的点 
{
    if(!k) return;
    else
    {
        if(w[x]==k)
        {
            if(cnt[x]) --cnt[x];
        }
        else
        {
            if(w[x]<k) del(rc[x],k);
            else del(lc[x],k);
        }
        calc(x);
        if(canrbu(x)) rbu(x);
    }
}
int up_bound(int x,int k)//在x的子树中找到大于k的最小数的名次 
{
    if(!x) return 1;
    else if(w[x]==k&&cnt[x])
        return delt[lc[x]]+1+cnt[x];
    else if(k<w[x])
        return up_bound(lc[x],k);
    else return delt[lc[x]]+cnt[x]+up_bound(rc[x],k); 
} 
int up_great(int x,int k)//在x的子树中找到小于k的最大数的名次 
{
    if(!x) return 0;
    else if(w[x]==k&&cnt[x])
        return delt[lc[x]];
    else if(w[x]<k)
        return delt[lc[x]]+cnt[x]+up_great(rc[x],k);
    else return up_great(lc[x],k);
}
int rk(int x)//求值为x的数在树中的排名 
{
    return up_great(rt,x)+1;
}
int kth(int x,int k)//在x的子树中查找名次为k的值 
{
    if(!x) return 0;
    else if(delt[lc[x]]<k&&k<=delt[lc[x]]+cnt[x]) return w[x];
    else if(delt[lc[x]]+cnt[x]<k)
        return kth(rc[x],k-delt[lc[x]]-cnt[x]);
    else return kth(lc[x],k);
}
int pre(int x,int k)//求x的前驱,即小于x的最大数 
{
    return kth(x,up_great(x,k));
}
int nxt(int x,int k)//求x的后继,即大于x的最小值 
{
    return kth(x,up_bound(x,k));
}
int read()
{
    char ch=getchar();
    int s=0,f=1;
    while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
    while('0'<=ch&&ch<='9') {s=s*10+ch-'0';ch=getchar();}
    return s*f;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)
    {
        int x;
        x=read();
        insert(rt,x);
    }
    int last=0;
    for(int i=1;i<=m;++i)
    {
        int opt,x;
        opt=read();x=read();
        x^=last;
        if(opt==1) 
        {
            insert(rt,x);
        }
        if(opt==2)
        {
            del(rt,x);
        }
        if(opt==3)
        {
            last=rk(x);
            ans^=last;
        }
        if(opt==4)
        {
            last=kth(rt,x);
            ans^=last;
        }
        if(opt==5)
        {
            last=pre(rt,x);
            ans^=last;
        }
        if(opt==6)
        {
            last=nxt(rt,x);
            ans^=last;
        }
    }
    printf("%d",ans);
    return 0;
}

by UltiMadow @ 2020-11-05 20:03:32

没卡替罪羊啊,我用替罪羊写的过了(


by cbdsopa @ 2020-11-05 20:04:46

那我写的太丑了吧,MLE第6个点


by cbdsopa @ 2020-11-05 20:12:18

应该哪个递归爆了


by 胖头鱼学员 @ 2020-11-06 08:30:58

很显然,有些操作冗余的,或者是哪里没处理好。


by cbdsopa @ 2020-11-06 13:55:20

过了,x打成k了


|