• CF455D Serega and Fun


    听同机房大佬sky说这是平衡树好题,再加上本蒟蒻刚刚学习平衡树,所以写个题解加深记忆。

    Solution

    我们看见一操作是移动操作(连个修改都没有),可以想到拿平衡树进行维护整个序列,这是很显然的。

    然后看二操作,询问区间某个数的出现次数。

    好像我所学过的平衡树是没有这种技能的(可能是我太菜没听说),本想去看看数据范围是不是除了平衡树还有别的啥,发现 (k_ileq n) ,那么可以拿 (n) 棵平衡树去维护相同值的元素的相对位置。

    现在就可以说点关于这 (n+1) 棵平衡树的事了。

    我们设 (t_0) 为维护整个序列的平衡树, (t_i) 是值为 (i) 的元素所在的平衡树,他们的 (key) 是这个元素在序列中的位置。

    维护 (t_0) 就用正常的操作,但维护 (t_i) 是需要找到位置不超过/不小于给定值的最靠右/最靠左元素,这个是需要给定值在原序列中的位置,即 (t_0) 中的位置,所以还需要记录 (t_i) 的点在 (t_0) 中的对应点。

    时间复杂度: (O(n+mlog n))

    注:作者使用 (splay) ,并且不会使用指针,所以拿的结构体。码风丑陋见谅。

    代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    
    using namespace std;
    const int N=3e5+10;
    int rt[N],cnt,b[N],bel[N],lans,n,m;
    struct node{
        int fa,siz,val;
        int son[2];
    }tr[N];
    
    inline int read(){
        int x=0,f=1;
        char ch=getchar();
        while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
        while(isdigit(ch)){x=x*10+(ch^48);ch=getchar();}
        return x*f;
    }
    
    inline bool which_son(int x){
        return x==tr[tr[x].fa].son[1];
    }
    
    inline void pushup(int x){
        tr[x].siz=tr[tr[x].son[0]].siz+tr[tr[x].son[1]].siz+1;
    }
    
    int newnode(int f,int x){
        tr[x].siz=1;
        tr[x].son[0]=tr[x].son[1]=0;
        tr[x].fa=f;
        return x;
    }
    
    inline void rotate(int x){
        int f=tr[x].fa,ff=tr[f].fa;
        bool w=which_son(x);
        tr[f].son[w]=tr[x].son[w^1];
        tr[tr[x].son[w^1]].fa=f;
        tr[x].fa=ff;
        tr[x].son[w^1]=f;
        tr[f].fa=x;
        if(ff){
            tr[ff].son[tr[ff].son[1]==f]=x;
        }
        pushup(f);pushup(x);
    }
    
    inline void splay(int x,int goal){
        for(int f;(f=tr[x].fa)!=goal;){
            if(tr[f].fa!=goal){
                rotate(which_son(x)==which_son(f)?f:x);
            }
            rotate(x);
        }
        if(goal==0){
            rt[bel[x]]=x;
        }
    }
    
    inline void insert(int f,int p,int x){
        if(!f) rt[bel[x]]=newnode(0,x);
        else{
            tr[f].son[p]=newnode(f,x);
            splay(x,0);
        }
    }
    
    int find(int x,int k){  //排名为k的编号
    	if(!x||tr[x].siz<k) return 0;
    	while(x){
    		if(k==tr[tr[x].son[0]].siz+1) break;
    		if(k>tr[tr[x].son[0]].siz+1) k-=tr[tr[x].son[0]].siz+1,x=tr[x].son[1];
    		else x=tr[x].son[0];
    	}
    	return x;
    }
    
    inline int pre(int x){
        int now=tr[x].son[0];
        while(tr[now].son[1]) now=tr[now].son[1];
        return now;
    }
    
    inline int nxt(int x){
        int now=tr[x].son[1];
        while(tr[now].son[0]) now=tr[now].son[0];
        return now;
    }
    
    inline void del(int &r,int x){
        int q=pre(r),p=nxt(r);
        if(!q&&!p){
            r=0;return ;
        }
        if(!q){
            splay(p,0);
            tr[p].son[0]=0;
            pushup(p);
            return ;
        }
        if(!p){
            splay(q,0);
            tr[q].son[1]=0;
            pushup(q);
            return ;
        }
        splay(q,0);splay(p,q);
        tr[p].son[0]=0;
        pushup(p);pushup(q);
    }
    
    int ans;
    inline int s_ize(int x){
        x-=n;
        splay(x,0);
        return tr[tr[x].son[0]].siz+1;
    }
    
    inline void _pre(int x,int lim){    //不小于最靠左
        if(!x) return ;
        while(x){
            if(s_ize(x)>=lim) ans=x,x=tr[x].son[0];
            else x=tr[x].son[1];
        }
    }
    
    inline void _nxt(int x,int lim){    //不大于最靠右
        if(!x) return ;
        while(x){
            if(s_ize(x)<=lim) ans=x,x=tr[x].son[1];
            else x=tr[x].son[0];
        }
    }
    
    inline void change(int k,int k1){
        splay(k,0);
        del(rt[bel[k]],k);
        splay(k1,0);
        if(tr[tr[k1].son[0]].siz==0) insert(k1,0,k);
        else{
           int q=pre(rt[bel[k1]]);
            splay(q,k1);insert(q,1,k);
        }
    }
    
    inline void moving(int l,int r){
        if(l==r) return ;
        int k=find(rt[0],r),k1=find(rt[0],l);
        change(k,k1);
        ans=0;
        _pre(rt[tr[k].val],l);
        if(ans==k+n) return ;
        change(k+n,ans);
    }
    
    inline void query(int l,int r,int k){
        int t=lower_bound(b+1,b+n+1,k)-b;
        if(!rt[t]||b[t]!=k){
            printf("%d
    ",lans=0);
            return ;
        }
        k=t;
        int k1,k2;ans=0;
        _pre(rt[k],l),k1=ans,ans=0;
        _nxt(rt[k],r),k2=ans,ans=0;
        if(k1==k2&&k1){
            puts("1");lans=1;
        }
        else if(!k1||!k2||s_ize(k1)>s_ize(k2)){
            puts("0");lans=0;
        }
        else{
            splay(k1,0);splay(k2,k1);
            printf("%d
    ",lans=tr[tr[k2].son[0]].siz+2);
        }
    }
    
    int main(){
        n=read();
        for(int i=1;i<=n;i++)
            tr[i].val=read(),b[i]=tr[i].val;
         sort(b+1,b+n+1);
        // cnt=unique(b+1,b+n+1)-b-1;
        for(int i=1;i<=n;i++)
            tr[i].val=lower_bound(b+1,b+n+1,tr[i].val)-b;
        for(int i=1;i<=n;i++)
            bel[i]=0,insert(rt[0],1,i);
        for(int i=1;i<=n;i++)
            bel[i+n]=tr[i].val,insert(rt[tr[i].val],1,i+n);
        m=read();
        for(int i=1,op,l,r,k;i<=m;i++){
            op=read(),l=read(),r=read();
            l=(l+lans-1)%n+1,r=(r+lans-1)%n+1;
            if(l>r) swap(l,r);
            if(op==1) moving(l,r);
            else k=(read()+lans-1)%n+1,query(l,r,k);
        }
        return 0;
    }
    

    本题分块做法不再说明( ̄▽ ̄)"

  • 相关阅读:
    RBF高斯径向基核函数【转】
    Libsvm自定义核函数【转】
    .Net对比Java分析
    码云提交
    webapi自定义Filter
    QT4.8.5 连接数据库(读写数据)
    axure8.0激活
    photo型的object转byte[]
    select拼接
    【转】easyui $.message.alert 点击右上角的关闭按钮时,不执行定义的回调函数
  • 原文地址:https://www.cnblogs.com/jasony/p/13817578.html
Copyright © 2020-2023  润新知