zoukankan      html  css  js  c++  java
  • 题解 P5217 【贫穷】

    原文链接

    ​ 看完题目我们都知道是平衡树,而且是要资瓷区间操作的平衡树,并且要能区间翻转,所以我们被迫选择自带三倍大常数(Splay),剩下的都是一些平衡树的基操了。

    操作(1) :插入,很简单。该怎么插就怎么插

    操作(2) :删除,直接删除。

    操作(3) :翻转,将要操作的子树旋转出来,然后直接打标记翻转。

    操作(4) :开始时将整个序列(build)出来,然后用数组将原序列在平衡树中的位置记录下来。平衡树中的一个点被删除后就给那个点打上标记,查询时直接查对应的位置,如果被删除后就输出(0),否则先(dfs)将路上的标记(pushdown)下来,然后再旋转到根输出排名即可。

    操作(5) :第(k)小,直接输出即可。

    操作(6) :状压压字母,将要操作的子树旋转出来,然后直接输出。

    细节

    (1.)

    推荐使用一个这样的函数:

    inline int split(int l,int r)
    {
        int x=rnk(l-1),y=rnk(r+1);
        splay(x,0);splay(y,x);
        return lc(y);
    }
    

    (rnk)就是找第(k)个位置。

    然后你要插入就

    int u=split(pos,pos-1);
    

    删除就

    int u=split(pos,pos);
    

    找区间就

    int u=split(l,r);
    

    (2.)

    为了不使我们(split)时越界,我们就在首尾搞两个字母,然后要把读入后的位置(++)

    然后呢?然后就完了。

    上代码:

    inline int ids(int u) {return u==rc(fc(u));}
    inline void connect(int u,int f,int s) {fc(u)=f;tr[f].ch[s]=u;}
    inline void pushup(int u)
    {
        if(!u) return;
        tr[u].siz=tr[lc(u)].siz+tr[rc(u)].siz+1;
        tr[u].valt=tr[lc(u)].valt|tr[rc(u)].valt|(1<<tr[u].val);
    }
    inline void update(int u)
    {
        tr[u].rev^=1;
        swap(lc(u),rc(u));
    }
    
    inline void pushdown(int u)
    {
        if(!tr[u].rev) return;
        if(lc(u)) update(lc(u));
        if(rc(u)) update(rc(u));
        tr[u].rev=0;
    }
    
    inline void rotate(int u)
    {
        int f=fc(u),ff=fc(f),s1=ids(u),s2=ids(f);
        connect(tr[u].ch[s1^1],f,s1);connect(f,u,s1^1);connect(u,ff,s2);
        pushup(f);pushup(u);
    }
    
    inline void splay(int u,int to)
    {
        while(fc(u)!=to)
        {
            if(fc(fc(u))==to) rotate(u);
            else if(ids(u)==ids(fc(u))) rotate(fc(u)),rotate(u);
            else rotate(u),rotate(u);
        }
    }
    
    inline int rnk(int k)
    {
        int u=root;
        while(u)
        {
            pushdown(u);
            if(tr[lc(u)].siz+1==k) return u;
            else if(tr[lc(u)].siz>=k) u=lc(u);
            else k=k-tr[lc(u)].siz-1,u=rc(u);
        }
    }
    
    inline int split(int l,int r)
    {
        int x=rnk(l-1),y=rnk(r+1);
        splay(x,0);splay(y,x);
        return lc(y);
    }
    
    inline void insert(int pos,int val)
    {
        split(pos,pos-1);
        int u=rc(root),v=++utot;lc(u)=v;
        tr[v].siz=1;tr[v].fa=u;tr[v].val=val;tr[v].valt=(1<<val);
        pushup(u);pushup(fc(u));pushup(fc(fc(u)));
    }
    
    inline void erase(int pos)
    {
        int u=split(pos,pos);delt[u]=1;
        lc(fc(u))=0;fc(u)=0;
    }
    
    inline void reverse(int l,int r)
    {
        int u=split(l,r);
        update(u);
    }
    
    void prepush(int u)
    {
        if(!u) return;
        prepush(fc(u));pushdown(u);
    }
    
    inline int getpos(int pos)
    {
        if(delt[used[pos]]) return 1;
        const int &u=used[pos];
        prepush(u);splay(u,0);
        return tr[lc(u)].siz+1;
    }
    
    inline int getcol(int l,int r)
    {
        int u=split(l,r),res=0;u=tr[u].valt;
        while(u) res++,u=u-(u&(-u));
        return res;
    }
    
    int build(int l,int r,int f)
    {
        if(l>r) return 0;
        int mid=(l+r)>>1,u=++utot;
        fc(u)=f;used[mid]=u;tr[u].siz=1;
        if(mid!=1&&mid!=n+2) tr[u].val=pre[mid]-'a',tr[u].valt=1<<tr[u].val;
        lc(u)=build(l,mid-1,u);
        rc(u)=build(mid+1,r,u);
        pushup(u);
        return u;
    }
    
    template<typename T>
    inline void read(T &x)
    {
        char c;int f=1;
        while(!isdigit(c=getchar())) (c=='-')&&(f=-1);
        x=c^48;
        while(isdigit(c=getchar())) x=x*10+(c^48);
        x*=f;
    }
    
    int main()
    {
        int x,y,t;
        char in[10],opt[10];
        read(n);read(t);
        scanf("%s",pre+2);
        root=build(1,n+2,root);
        while(t--)
        {
            scanf("%s",opt);read(x);x++;
            if(opt[0]=='I') scanf("%s",in),insert(x+1,in[0]-'a');
            else if(opt[0]=='D') erase(x);
            else if(opt[0]=='R') read(y),y++,reverse(x,y);
            else if(opt[0]=='P') printf("%d
    ",getpos(x)-1);
            else if(opt[0]=='T') printf("%c
    ",(char)tr[rnk(x)].val+'a');
            else read(y),y++,printf("%d
    ",getcol(x,y));
        }
        return 0;
    }
    
  • 相关阅读:
    C++结构体中sizeof
    sizeof()的用法
    XStream和Json
    省市联动
    ajax
    配置文件的读取
    JSP标签库
    字符串函数参数传入传出(去空格)
    字符串函数参数传入传出(字符串反转)
    opendir,readdir,closedir
  • 原文地址:https://www.cnblogs.com/gxm123/p/13604618.html
Copyright © 2011-2022 走看看