zoukankan      html  css  js  c++  java
  • SuperMemo(Splay区间操作)

    学习链接:https://blog.csdn.net/ztzshiwo_cnyali/article/details/52221503

    题目链接:http://poj.org/problem?id=3580

    POJ 3580

    splay超全模板题...

    总共有6种操作,分别为MIN,INSERT,ADD,DELETE,REVERSE,REVOLVE六种,下面会分别介绍格式与方法

    首先输入N以及N个数,接下来输入M,即操作个数,接下来M行包含操作,具体格式如下

    1.MIN a b 求a,b区间的最小值

    2.ADD a b c 对a,b区间的每个数添加c

    3.DELETE a 将第a个数删除

    4.INSERT a b 在第a个数后面添加一个数b

    5.REVERSE a,b 将a,b区间每个数翻转 如 REVERSE 2 4 (1,2,3,4,5)-->(1,4,3,2,5)

    6.REVOLVE a,b,c 将a,b区间作为一个环 然后旋转c次(这是我的理解... ...)

    如 REVOVLE 2 4 1 (1,2,3,4,5)-->(1,4,2,3,5)

    REVOVLE 2 4 2 (1,2,3,4,5)-->(1,3,4,2,5)

    然后这里面的c有可能是负数并且很大... ... 所以要取模

    讲一下算法思想:

    构建一棵splay树 储存父亲 左右儿子 翻转标记 增加标记 最小值 本身的值 以此节点为根的子树的节点数 (size)

    首先将1~n节点添加进去 同时要在最前面和最后面添加一个节点(具体理由后面讲)

    基本函数:update(更新这个节点的MIN值与size),splay(将一个点旋转到目标位置),rotateto(找到第k个节点并旋转到目标位置),pushdown(将增加标记(add)与翻转标记(rev)推到下一层节点),newnode(构建一个新节点,节点序号为cnt)

    讲讲每个操作的具体操作方法

    1.MIN a,b 将第a个节点旋到根节点,将第b+2个节点旋到根节点的右子树,注意:因为前面添加了一个节点,所以原来第a个节点为现在的第a+1个节点 所以现在根节点右节点的左子树就代表以前的 a,b区间,只要输出它的MIN就可以了

    2.ADD a,b,c 同理 将第a个节点旋到根节点,将第b+2个节点旋到根节点的右子树,给根节点右节点的左子树增加标记与数值,最小值添加c

    3.DELETE a 将第a个节点旋到根节点,第a+2个节点旋到根节点的右节点,那么根节点右节点的左子树有且仅有a+1这个节点(即原来的第a个节点),那么断绝他们的父子关系就可以了

    4.INSERT a b 将第a个节点旋到根节点,第a+1个节点旋到根节点的右节点,那么根节点右节点的左子树绝对没有节点,同样添加一个值为b的新节点,然后建立关系

    5.REVERSE a,b 与ADD相似 只要改变一下将第a个节点旋到根节点,将第b+2个节点旋到根节点的右子树,给根节点右节点的左子树更改REV标记

    6.REVOLVE a,b,c这个操作有一点复杂... ...实际上可以看出 这就是将这个区间里面分成两个部分然后交换位置,那我们先通过旋转找到这一段区间,将它从父亲节点那里并记录位置,然后又找到另一端区间的位置,将之前存下来区间放在这个区间的前面,就可以实现,这一段需要一定的理解,可以手动模拟一下发现规律,具体见代码

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    const int maxn=400010;
    using namespace std;
    int rt,m,n,a[maxn],cnt;
    int val[maxn],Min[maxn],add[maxn],rev[maxn];
    int ls[maxn],rs[maxn],fa[maxn],sz[maxn];
    void newnode(int v)
    {
        sz[++cnt]=1;
        val[cnt]=Min[cnt]=v;
        fa[cnt]=ls[cnt]=rs[cnt]=add[cnt]=rev[cnt]=0;
    }
    void update(int x)
    {
        sz[x]=sz[ls[x]]+sz[rs[x]]+1;
        Min[x]=val[x];
        if(ls[x]&&Min[ls[x]]<Min[x])Min[x]=Min[ls[x]];
        if(rs[x]&&Min[rs[x]]<Min[x])Min[x]=Min[rs[x]];
    }
    void pushdown(int x)
    {
        if(add[x]!=0)
        {
            if(ls[x])
            {
                add[ls[x]]+=add[x];
                Min[ls[x]]+=add[x];
                val[ls[x]]+=add[x];
            }
            if(rs[x])
            {
                add[rs[x]]+=add[x];
                Min[rs[x]]+=add[x];
                val[rs[x]]+=add[x];
            }
            add[x]=0;
        }
        if(rev[x])
        {
            if(ls[x])rev[ls[x]]^=1;
            if(rs[x])rev[rs[x]]^=1;
            swap(ls[x],rs[x]);
            rev[x]=0;
        }
    }
    void build(int x,int f)
    {
        if(x==n+2)return;
        newnode(a[x]);
        if(f)
        {
            fa[cnt]=f;
            rs[f]=cnt;
        }
        else rt=cnt;
        int now=cnt;
        build(x+1,cnt);
        update(now);
    }
    void init()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        build(0,0);
    }
    void rrotate(int x)
    {
        int y=ls[x],k=fa[x];
        ls[x]=rs[y];
        if(ls[x])fa[ls[x]]=x;
        fa[x]=y;fa[y]=k;rs[y]=x;
        if(k==0)rt=y;
        else 
        if(ls[k]==x)ls[k]=y;
        else rs[k]=y;
        update(x);
    }
    void lrotate(int x)
    {
        int y=rs[x],k=fa[x];
        rs[x]=ls[y];
        if(rs[x])fa[rs[x]]=x;
        ls[y]=x;fa[x]=y;fa[y]=k;
        if(k==0)rt=y;
        else 
        if(ls[k]==x)ls[k]=y;
        else rs[k]=y;
        update(x);
    }
    void splay(int x,int f)
    {
        int y,z;
        while(1)
        {
            if((y=fa[x])==f)break;
            if((z=fa[y])==f)
            {
                if(ls[y]==x)rrotate(y);
                else lrotate(y);
            }
            else
            {
                if(ls[z]==y)
                {
                    if(ls[y]==x)rrotate(z),rrotate(y);
                    else lrotate(y),rrotate(z);
                }
                else
                {
                    if(rs[y]==x)lrotate(z),lrotate(y);
                    else rrotate(y),lrotate(z);
                }
            }
        }
        return;
    }
    void rotateto(int k,int f)
    {
        int i=rt;
        while(1)
        {
            pushdown(i);
            int lsum=sz[ls[i]]+1;
            if(k==lsum)break;
            if(k<lsum)i=ls[i];
            else k-=lsum,i=rs[i];
        }
        splay(i,f);
    }
    void ADD(int x,int y,int z)
    {
        rotateto(x,0);
        rotateto(y+2,rt);
        int k=ls[rs[rt]];
        add[k]+=z,val[k]+=z,Min[k]+=z;
    }
    void insert(int x,int y)
    {
        rotateto(x+1,0);rotateto(x+2,rt);
        newnode(y);
        ls[rs[rt]]=cnt;
        fa[cnt]=rs[rt];
    }
    void del(int x)
    {
        rotateto(x,0);rotateto(x+2,rt);
        ls[rs[rt]]=0;
    }
    void MIN(int x,int y)
    {
        rotateto(x,0);rotateto(y+2,rt);
        printf("%d
    ",Min[ls[rs[rt]]]);
    }
    void reverse(int x,int y)
    {
        if(x==y)return;
        rotateto(x,0);rotateto(y+2,rt);
        rev[ls[rs[rt]]]^=1;
    }
    void revolve(int x,int y,int z)
    {
        int p=(y-x+1),k,t;
        k=(z%p+p)%p;
        if(k)
        {
            rotateto(y-k+1,0);rotateto(y+2,rt);
            t=ls[rs[rt]];
            ls[rs[rt]]=0;
            rotateto(x,0);rotateto(x+1,rt);
            ls[rs[rt]]=t;
            fa[t]=rs[rt];
        }
    }
    void solve()
    {
        int x,y,z;
        char s[10];
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",s);
            if(s[0]=='A')
            {
                scanf("%d%d%d",&x,&y,&z);
                ADD(x,y,z);
            }
            else
            if(s[0]=='I')
            {
                scanf("%d%d",&x,&y);
                insert(x,y);
            }
            else
            if(s[0]=='D')
            {
                scanf("%d",&x);
                del(x);
            }
            else
            if(s[0]=='M')
            {
                scanf("%d%d",&x,&y);
                MIN(x,y);
            }
            else
            if(s[0]=='R')
            {
                if(s[3]=='O')
                {
                    scanf("%d%d%d",&x,&y,&z);
                    revolve(x,y,z);
                }
                else
                {
                    scanf("%d%d",&x,&y);
                    reverse(x,y);
                }
            }
        }
        return;
    }
    int main()
    {
        init();
        solve();
        return 0;
    }
    当初的梦想实现了吗,事到如今只好放弃吗~
  • 相关阅读:
    wampserver的安装及使用配置方法
    关于数据未渲染完,要获取document高度问题——ajax全局事件
    浏览器内核及对应兼容性的处理问题
    [PHP]php缓冲 output_buffering的使用详解
    [PHP]PDO各方法在发生MYSQL断开时的反应
    [算法]浮点数在内存中的存储方式
    [PHP]session回收机制及php.ini session生命期
    [Linux][HTTP] Cookie和Set-Cookie
    [MySQL]多表关联查询技巧
    [MySql]索引的一些技巧
  • 原文地址:https://www.cnblogs.com/caijiaming/p/11630344.html
Copyright © 2011-2022 走看看