bzoj 3217 ALOEXT 替罪羊树套trie树

感觉又刚了一遍带插入区间k小值。。。
这题写个替罪羊练一下。其实应该可以用重量平衡的treap套trie。

带插入维护一段区间的trie和次小值。
区间次小值随便维护,区间trie呢?
我会做!替罪羊套trie!
不过写到一半你会发现这题还有删除。

treap删点直接旋到下面删。那替罪羊怎么删?
直接重构?每次删中间的点就挂了。
打标记? 似乎会有很多特判。
只要像线段树一样建就好了。把所有的表示元素的点都放在叶节点,其他点都是空点。只维护子树中所有叶节点形成的trie。
插入时新建两个点,删除时直接删除叶节点。
查询时像线段树一样找到log个区间,然后类似主席树地跑。

#include <bits/stdc++.h>
using namespace std;
#define A 20
#define alp 0.93
#define N 1100000
#define M 35000000
#define ls(x) ch[x][0]
#define rs(x) ch[x][1]
#define which(x) (ch[fa[x]][1]==x)
int a[N],n,m,n0,ans;
int st[210],top;
char s[11];
struct Trie
{
    int ch[M][2],num[M],cnt;
    queue<int>q;
    int ap()
    {
        if(!q.empty())
        {
            int ret=q.front();q.pop();
            ls(ret)=rs(ret)=0;num[ret]=0;
            return ret;
        }
        return ++cnt;
    }
    void del(int x)
    {
        if(!x)return;
        q.push(x);
        del(ls(x));del(rs(x));
    }
    void insert(int &now,int v,int deep,int tp)
    {
        if(!now)now=ap();
        num[now]+=tp;
        if(deep==-1)return;
        if(v>>deep&1)insert(rs(now),v,deep-1,tp);
        else insert(ls(now),v,deep-1,tp);
    }
    int merge(int x,int y)
    {
        if(!x&&!y)return 0;
        int ret=ap();
        ls(ret)=merge(ls(x),ls(y));
        rs(ret)=merge(rs(x),rs(y));
        num[ret]=num[x]+num[y];
        return ret;
    }
    int query(int x,int deep)
    {
        if(deep<0)return 0;
        int t=x>>deep&1,sum=0;
        for(int i=1;i<=top;i++)
            sum+=num[ch[st[i]][t^1]];
        for(int i=1;i<=top;i++)
            st[i]=ch[st[i]][sum ? t^1:t];
        return query(x,deep-1)+(sum ? 1<<deep:0);
    }
}tr1;
struct node
{
    int mx,sx;
    node(){}
    node(int mx,int sx):mx(mx),sx(sx){}
    void ins(int x)
    {
        if(x>mx)sx=mx,mx=x;
        else if(x>sx)sx=x;
    }
};
node merge(node r1,node r2)
{
    node ret=r1;
    ret.ins(r2.mx);ret.ins(r2.sx);
    return ret;
}
struct Sheep
{
    queue<int>q;
    int ch[N][2],size[N],root[N],fa[N],val[N],sz[N],bj[N];
    int cnt,rt,fre,pre,tar;
    node v[N],n1;
    int ap()
    {
        if(!q.empty())
        {
            int t=q.front();q.pop();
            ls(t)=rs(t)=size[t]=root[t]=fa[t]=val[t]=bj[t]=0;
            v[t]=node(0,0);
            return t;
        }
        return ++cnt;
    }
    int newnode(int x)
    {
        int ret=ap();bj[ret]=1;
        val[ret]=x;size[ret]=sz[ret]=1;
        v[ret]=node(x,0);
        tr1.insert(root[ret],x,A,1);
        return ret;
    }
    void pushup(int x)
    {
        size[x]=size[ls(x)]+size[rs(x)];
        sz[x]=size[x]+1;
        root[x]=tr1.merge(root[ls(x)],root[rs(x)]);
        v[x]=merge(v[ls(x)],v[rs(x)]);
        fa[ls(x)]=fa[rs(x)]=x;
    }
    int build(int l,int r)
    {
        if(l>r)return 0;
        if(l==r)return newnode(a[l]);

        int mid=(l+r)>>1,ret=ap();
        ls(ret)=build(l,mid);
        rs(ret)=build(mid+1,r);
        pushup(ret);
        return ret;
    }
    void dfs(int x)
    {
        if(!x)return;
        q.push(x);tr1.del(root[x]);
        if(bj[x]){a[++n]=val[x];return;}
        dfs(ls(x));dfs(rs(x));
    }
    void reb(int x)
    {
        tr1.del(root[x]);
        n=0;dfs(ls(x));dfs(rs(x));
        int t=build(1,n);
        if(x==rt)rt=t;
        fa[t]=fa[x];
        ch[fa[x]][which(x)]=t;
    }
    void insert(int &now,int x,int y)
    {
        if(size[now]==1||!now)
        {
            int t=newnode(y),ret=ap();
            fa[ret]=pre;ls(ret)=t;rs(ret)=now;
            pushup(ret);now=ret;
            return;
        }
        pre=now;
        if(size[ls(now)]>=x)insert(ls(now),x,y);
        else insert(rs(now),x-size[ls(now)],y);

        tr1.insert(root[now],y,A,1);
        v[now].ins(y);size[now]++;sz[now]+=2;

        fa[ls(now)]=fa[rs(now)]=now;
        if(max(sz[ls(now)],sz[rs(now)])>sz[now]*alp)
            fre=now;
    }
    void del(int &now,int x)
    {
        if(bj[now])
        {q.push(now);tar=val[now];now=0;return;}

        if(size[ls(now)]>=x)del(ls(now),x);
        else del(rs(now),x-size[ls(now)]);

        tr1.insert(root[now],tar,A,-1);
        v[now]=merge(v[ls(now)],v[rs(now)]);
        size[now]--;sz[now]--;

        fa[ls(now)]=fa[rs(now)]=now;
        if(max(sz[ls(now)],sz[rs(now)])>sz[now]*alp)
            fre=now;
    }
    void insert(int x,int y)
    {
        fre=0;insert(rt,x,y);
        if(fre)reb(fre);
    }
    void del(int x)
    {
        fre=0;del(rt,x);
        if(fre)reb(fre);
    }
    void find(int now,int pre,int x,int y)
    {
        if(pre+1>=x&&pre+size[now]<=y)
        {
            st[++top]=root[now];
            n1=merge(n1,v[now]);
            return;
        }
        if(pre+size[ls(now)]>=x)
            find(ls(now),pre,x,y);
        if(pre+size[ls(now)]<y)
            find(rs(now),pre+size[ls(now)],x,y);
    }
    node find(int x,int y)
    {
        top=0;n1=node(0,0);
        find(rt,0,x,y);
        return n1;
    }
}tr2;
int main()
{
    scanf("%d%d",&n,&m);n0=n;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    tr2.rt=tr2.build(1,n);
    for(int x,y;m--;)
    {
        scanf("%s",s);
        if(s[0]=='I')
        {
            scanf("%d%d",&x,&y);
            x=(x+ans)%n0+1;y=(y+ans)%(1<<A);n0++;
            tr2.insert(x,y);
        }
        else if(s[0]=='D')
        {
            scanf("%d",&x);
            x=(x+ans)%n0+1;n0--;
            tr2.del(x);
        }
        else if(s[0]=='C')
        {
            scanf("%d%d",&x,&y);
            x=(x+ans)%n0+1;y=(y+ans)%(1<<A);
            tr2.del(x);
            tr2.insert(x,y);
        }
        else
        {
            scanf("%d%d",&x,&y);
            x=(x+ans)%n0+1;y=(y+ans)%n0+1;
            node t=tr2.find(x,y);
            printf("%d\n",ans=tr1.query(t.sx,A));
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值