BZOJ 3196 Tyvj 1730 二逼平衡树

树套树裸题,练习模板的好去处。
注意每次SpLay修改前对原串的变动。

/**************************************************************
    Problem: 3196
    User: vermouth
    Language: C++
    Result: Accepted
    Time:8124 ms
    Memory:123440 kb
****************************************************************/
 
#include<cstdio>
#include<iostream>
using namespace std;
#define lson l,m,root<<1
#define rson m+1,r,root<<1|1
#define inf 0x3f3f3f3f 
const int maxn=250100;
 
struct Splaytree
{
    int sz[maxn*20];
    int ch[maxn*20][2];
    int pre[maxn*20],rt[maxn<<2],top;
    inline void up(int x)
    {
        sz[x] = sz[ch[x][0]]+sz[ch[x][1]]+cnt[x];
    }
    inline void rotate(int x,int f)
    {
        int y=pre[x];
        ch[y][!f]=ch[x][f];
        pre[ch[x][f]]=y;
        pre[x]=pre[y];
        if(pre[x]) ch[pre[y]][ch[pre[y]][1]==y]=x;
        ch[x][f]=y;
        pre[y]=x;
        up(y);
    }
    inline void Splay(int x,int goal,int root)
    {
        while(pre[x]!=goal)
        {
            if(pre[pre[x]]==goal) rotate(x,ch[pre[x]][0]==x);
            else {
                int y=pre[x],z=pre[y];
                int f=(ch[z][0]==y);
                if(ch[y][f]==x) rotate(x,!f),rotate(x,f);
                else rotate(y,f),rotate(x,f);
            }
        }
        up(x);
        if(goal==0) rt[root]=x;
    }
    inline void RTO(int k,int goal,int root)
    {
        int x=rt[root];
        while(sz[ch[x][0]]!=k-1)
        {
            if(k<sz[ch[x][0]]+1) x=ch[x][0];
            else {
                k-=(sz[ch[x][0]]+1);
                x=ch[x][1];
            }
        }
        Splay(x,goal,root);
    }
    inline void Newnode(int &x,int c)
    {
        x=++top;
        ch[x][0]=ch[x][1]=pre[x]=0;
        sz[x]=1;cnt[x]=1;
        val[x]=c;
    }
    inline void init(){
        top=0;
    }
    inline void Insert(int &x,int key,int f,int root){
        if(!x){
            Newnode(x,key);
            pre[x]=f;
            Splay(x,0,root);
            return ;
        }
        if(key==val[x]){
            cnt[x]++;
            sz[x]++;
            return ;
        }else if(key<val[x]){
            Insert(ch[x][0],key,x,root);
        }else{
            Insert(ch[x][1],key,x,root);
        }
        up(x);
    }
    void Del(int root){
        if(cnt[rt[root]]>1){
            cnt[rt[root]]--;
        }
        else
        {
            int t=rt[root];
            if(ch[rt[root]][1]){
                rt[root]=ch[rt[root]][1];
                RTO(1,0,root);
                ch[rt[root]][0]=ch[t][0];
                if(ch[rt[root]][0]) pre[ch[rt[root]][0]]=rt[root];
            }
            else rt[root]=ch[rt[root]][0];
            pre[rt[root]]=0;
        }
        up(rt[root]);
    }
    void findkey(int x,int key,int &ans)
    {
        if(!x) return ;
        if(val[x]==key) 
            ans=x;
        else if(val[x]>key)
            findkey(ch[x][0],key,ans);
        else
            findkey(ch[x][1],key,ans);
    }
    inline int find_kth(int x,int k,int root){
        if(k<sz[ch[x][0]]+1){
            return find_kth(ch[x][0],k,root);
        }else if(k>sz[ch[x][0]]+cnt[x])
            return find_kth(ch[x][1],k-sz[ch[x][0]]-cnt[x],root);
        else {
            Splay(x,0,root);
            return val[x];
        }
    }
    int findpre(int x,int z){
        int ans=-inf;
        while(ch[x][val[x]<=z])
        {
            if(val[x]<=z) ans=val[x];
            x=ch[x][val[x]<=z];
        }if(val[x]<=z) ans=max(ans,val[x]);
        return ans;
    }
    int findsuc(int x,int z){
        int ans=inf;
        while(ch[x][val[x]<z])
        {
            if(val[x]>=z) ans=val[x];
            x=ch[x][val[x]<z];
        }if(val[x]>=z) ans=min(ans,val[x]);
        return ans;
    }
    int val[maxn*20];
    int cnt[maxn*20];
    void build(int l,int r,int root)
    {
        rt[root]=0;
        for(int i=l;i<=r;i++)
            Insert(rt[root],a[i],0,root);
        if(l>=r) return ;
        int m=(l+r)>>1;
        build(lson);
        build(rson);
    }
    void update(int l,int r,int root,int i,int x)
    {
        int ans=0;
        findkey(rt[root],a[i],ans);
        Splay(ans,0,root);
        Del(root);
        Insert(rt[root],x,0,root);
        if(l>=r) return ;
        int m=(l+r)>>1;
        if(i<=m) update(lson,i,x);
        else update(rson,i,x);
    }
    int cntLess(int x,int key){
        int ret=0;
        while(x)
        {
            if(val[x]>key)
                x=ch[x][0];
            else
            {
                ret+=cnt[x]+sz[ch[x][0]];
                x=ch[x][1];
            }
        }
        return ret;
    }
    int getnumLess(int l,int r,int root,int L,int R,int x)
    {
        if(L<=l&&R>=r)
        {
            return cntLess(rt[root],x);
        }
        int m=(l+r)>>1;
        int ret=0;
        if(L<=m) ret+=getnumLess(lson,L,R,x);
        if(R>m) ret+=getnumLess(rson,L,R,x);
        return ret;
    }
    inline int get_pre(int l,int r,int root,int L,int R,int k)
    {
        if(L<=l&&R>=r)
        {
            return findpre(rt[root],k);
        }
        int ans=-inf;
        int m=(l+r)>>1;
        if(L<=m) ans=max(ans,get_pre(lson,L,R,k));
        if(R>m) ans=max(ans,get_pre(rson,L,R,k));
        return ans;
    }
    inline int get_suc(int l,int r,int root,int L,int R,int k)
    {
        if(L<=l&&R>=r)
        {
            return findsuc(rt[root],k);
        }
        int ans=inf;int m=(l+r)>>1;
        if(L<=m) ans=min(ans,get_suc(lson,L,R,k));
        if(R>m) ans=min(ans,get_suc(rson,L,R,k));
        return ans;
    }
    int search(int L,int R,int k)
    {
        int l=0,r=inf;
        int ans=0;
        while(l<=r)
        {
            int m=(l+r)>>1;
            int cnt=getnumLess(1,n,1,L,R,m);
            if(cnt>=k)
            {
                r=m-1;ans=m;
            }
            else l=m+1;
        }
        return ans;
    }
    void solve()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(1,n,1);
        for(int i=1;i<=m;i++)
        {
            int x,y,z,op;
            scanf("%d%d%d",&op,&x,&y);if(op!=3) scanf("%d",&z);
            if(op==1) printf("%d\n",getnumLess(1,n,1,x,y,z-1)+1);
            else if(op==2) printf("%d\n",search(x,y,z));
            else if(op==3) update(1,n,1,x,y),a[x]=y;
            else if(op==4) printf("%d\n",get_pre(1,n,1,x,y,z-1));
            else if(op==5) printf("%d\n",get_suc(1,n,1,x,y,z+1)); 
        }
    }
    int a[maxn];
    int n,m;
} spt;
int T; 
int main()
{
    spt.init();
    spt.solve();
    return 0;
}
/*
30 10
347297 7767863 4687361 4266761 1869189 6183125 6228737 7377798 2298221 253439 2279737 7603021 9596641 3461977 8857135 7648897 1264321 7381859 2257573 3750694 7066537 7631697 3115165 3367245 3742733 7943233 4901377 2381377 3162917 3567345 
1 7 26 2298221
3 19 6712240 
4 23 29 3743106
5 7 24 7624712
1 7 22 7066537
5 1 18 251894
2 19 21 1
5 15 16 8855774
2 1 12 10
3 15 3539397 
*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值