zoukankan      html  css  js  c++  java
  • POJ 3580 SuperMemo (Splay 区间更新、翻转、循环右移,插入,删除,查询)

    SuperMemo
    Time Limit: 5000MS   Memory Limit: 65536K
    Total Submissions: 13917   Accepted: 4352
    Case Time Limit: 2000MS

    Description

    Your friend, Jackson is invited to a TV show called SuperMemo in which the participant is told to play a memorizing game. At first, the host tells the participant a sequence of numbers, {A1A2, ... An}. Then the host performs a series of operations and queries on the sequence which consists:

    1. ADD x y D: Add D to each number in sub-sequence {Ax ... Ay}. For example, performing "ADD 2 4 1" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5, 5}
    2. REVERSE x y: reverse the sub-sequence {Ax ... Ay}. For example, performing "REVERSE 2 4" on {1, 2, 3, 4, 5} results in {1, 4, 3, 2, 5}
    3. REVOLVE x y T: rotate sub-sequence {Ax ... AyT times. For example, performing "REVOLVE 2 4 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 2, 5}
    4. INSERT x P: insert P after Ax. For example, performing "INSERT 2 4" on {1, 2, 3, 4, 5} results in {1, 2, 4, 3, 4, 5}
    5. DELETE x: delete Ax. For example, performing "DELETE 2" on {1, 2, 3, 4, 5} results in {1, 3, 4, 5}
    6. MIN x y: query the participant what is the minimum number in sub-sequence {Ax ... Ay}. For example, the correct answer to "MIN 2 4" on {1, 2, 3, 4, 5} is 2

    To make the show more interesting, the participant is granted a chance to turn to someone else that means when Jackson feels difficult in answering a query he may call you for help. You task is to watch the TV show and write a program giving the correct answer to each query in order to assist Jackson whenever he calls.

    Input

    The first line contains (≤ 100000).

    The following n lines describe the sequence.

    Then follows M (≤ 100000), the numbers of operations and queries.

    The following M lines describe the operations and queries.

    Output

    For each "MIN" query, output the correct answer.

    Sample Input

    5
    1 
    2 
    3 
    4 
    5
    2
    ADD 2 4 1
    MIN 4 5

    Sample Output

    5
    题意:给你一个序列以及许多操作,包括区间更新、翻转、循环右移,插入,删除,查询
    分析:都是Splay的一些基本的操作,更新和翻转使用lazy标记的思想就行了,对于循环右移,首先找出左端点移动的位置k,然后就是将[k,r]区间移动到[l,k-1]的前面去,我们可以先定位出[k,r],再调整出
    [l-1,l],将[k,r]接上去就行了。插入操作也是通过变换找到这个子树,再新加节点就是了。
    #include<stdio.h>
    #include<string.h>
    #include<iostream>
    using namespace std;
    
    #define Key_value ch[ch[root][1]][0]
    const int MAXN = 200000+100;
    const int INF = 0X3F3F3F3F;
    int fa[MAXN],ch[MAXN][2],key[MAXN],sz[MAXN],add[MAXN],rev[MAXN],mi[MAXN];
    int root,tot1;
    int s[MAXN],tot2;//内存池、内存池容量
    int a[MAXN];
    int n,m;
    
    void NewNode(int &r,int pre,int k)
    {
        if(tot2) r=s[tot2--];
        else r=++tot1;
        ch[r][0]=ch[r][1]=0;
        fa[r]=pre;
        sz[r]=1;
        add[r]=rev[r]=0;
        key[r]=mi[r]=k;
    }
    void Update_Rev(int r)
    {
        if(r==0) return;
        swap(ch[r][0],ch[r][1]);
        rev[r]^=1;
    }
    void Update_Add(int r,int val)
    {
        if(r==0) return;
        add[r]+=val;
        key[r]+=val;
        mi[r]+=val;
    }
    void Push_Up(int r)
    {
        sz[r]=sz[ch[r][0]]+sz[ch[r][1]]+1;
        mi[r]=key[r];
        if(ch[r][0]) mi[r]=min(mi[r],mi[ch[r][0]]);
        if(ch[r][1]) mi[r]=min(mi[r],mi[ch[r][1]]);
    }
    void Push_Down(int r)
    {
        if(rev[r])
        {
            Update_Rev(ch[r][0]);
            Update_Rev(ch[r][1]);
            rev[r]=0;
        }
        if(add[r])
        {
            Update_Add(ch[r][0],add[r]);
            Update_Add(ch[r][1],add[r]);
            add[r]=0;
        }
    }
    void Build(int &x,int l,int r,int pre)
    {
        if(l>r) return;
        int mid=(l+r)/2;
        NewNode(x,pre,a[mid]);
        Build(ch[x][0],l,mid-1,x);
        Build(ch[x][1],mid+1,r,x);
        Push_Up(x);
    }
    void Init()
    {
        root=tot1=tot2=0;
        ch[root][0]=ch[root][1]=sz[root]=add[root]=rev[root]=fa[root]=0;
        mi[root]=INF;
        NewNode(root,0,INF);
        NewNode(ch[root][1],root,INF);
        Build(Key_value,1,n,ch[root][1]);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void Rotate(int x,int d)
    {
        int y=fa[x];
        Push_Down(y);
        Push_Down(x);
        ch[y][!d]=ch[x][d];
        fa[ch[x][d]]=y;
        if(fa[y]) ch[fa[y]][ch[fa[y]][1]==y]=x;
        fa[x]=fa[y];
        ch[x][d]=y;
        fa[y]=x;
        Push_Up(y);
    }
    //伸展操作,将r调整到goal下面
    void Splay(int r,int goal)
    {
        Push_Down(r);
        while(fa[r]!=goal)
        {
            if(fa[fa[r]]==goal)
            {
                //这题有反转操作,需要先push_down,在判断左右孩子
                Push_Down(fa[r]);
                Push_Down(r);
                Rotate(r,ch[fa[r]][0]==r);
            }
            else
            {
                //这题有反转操作,需要先push_down,在判断左右孩子
                Push_Down(fa[fa[r]]);
                Push_Down(fa[r]);
                Push_Down(r);
                int y=fa[r];
                int d=(ch[fa[y]][0]==y);
                //两个方向不同,则先左旋再右旋
                if(ch[y][d]==r)
                {
                    Rotate(r,!d);
                    Rotate(r,d);
                }
                //两个方向相同,相同方向连续两次
                else
                {
                    Rotate(y,d);
                    Rotate(r,d);
                }
            }
        }
        Push_Up(r);
        if(goal==0) root=r;
    }
    int Get_Kth(int r,int k)
    {
        Push_Down(r);
        int t=sz[ch[r][0]]+1;
        if(t==k)return r;
        if(t>k)return Get_Kth(ch[r][0],k);
        else return Get_Kth(ch[r][1],k-t);
    }
    int Get_Min(int r)
    {
        Push_Down(r);
        while(ch[r][0])
        {
            r=ch[r][0];
            Push_Down(r);
        }
        return r;
    }
    void Erase(int r)
    {
        if(r)
        {
            s[++tot2]=r;
            Erase(ch[r][0]);
            Erase(ch[r][1]);
        }
    }
    int Get_Max(int r)
    {
        Push_Down(r);
        while(ch[r][1])
        {
            r=ch[r][1];
            Push_Down(r);
        }
        return r;
    }
    void update_add(int l,int r,int val)
    {
        Splay(Get_Kth(root,l),0);
        Splay(Get_Kth(root,r+2),root);
        Update_Add(Key_value,val);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void update_rev(int l,int r)
    {
        Splay(Get_Kth(root,l),0);
        Splay(Get_Kth(root,r+2),root);
        Update_Rev(Key_value);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void update_reve(int l,int r,int T)
    {
        int len=r-l+1;
        T=(T%len+len)%len;
        if(T==0) return;
        int k=r-T+1;
        Splay(Get_Kth(root,k),0);
        Splay(Get_Kth(root,r+2),root);
        int tmp=Key_value;
        Key_value=0;
        Push_Up(ch[root][1]);
        Push_Up(root);
        Splay(Get_Kth(root,l),0);
        Splay(Get_Kth(root,l+1),root);
        Key_value=tmp;
        fa[Key_value]=ch[root][1];
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void update_int(int x,int P)
    {
        Splay(Get_Kth(root,x+1),0);
        Splay(Get_Kth(root,x+2),root);
        NewNode(Key_value,ch[root][1],P);
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    void update_del(int x)
    {
        Splay(Get_Kth(root,x),0);
        Splay(Get_Kth(root,x+2),root);
        Erase(Key_value);
        fa[Key_value]=0;
        Key_value=0;
        Push_Up(ch[root][1]);
        Push_Up(root);
    }
    int query_min(int l,int r)
    {
        Splay(Get_Kth(root,l),0);
        Splay(Get_Kth(root,r+2),root);
        return mi[Key_value];
    }
    
    char str[20];
    int x,y,D,P,T;
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        Init();
        scanf("%d",&m);
        while(m--)
        {
            scanf("%s",str);
            if(strcmp(str,"ADD")==0)
            {
                scanf("%d%d%d",&x,&y,&D);
                update_add(x,y,D);
            }
            else if(strcmp(str,"REVERSE")==0)
            {
                scanf("%d%d",&x,&y);
                update_rev(x,y);
            }
            else if(strcmp(str,"REVOLVE")==0)
            {
                scanf("%d%d%d",&x,&y,&T);
                update_reve(x,y,T);
            }
            else if(strcmp(str,"INSERT")==0)
            {
                scanf("%d%d",&x,&P);
                update_int(x,P);
            }
            else if(strcmp(str,"DELETE")==0)
            {
                scanf("%d",&x);
                update_del(x);
            }
            else
            {
                scanf("%d%d",&x,&y);
                printf("%d
    ",query_min(x,y));
            }
        }
        return 0;
    }
     
  • 相关阅读:
    从Android APP里面打开其他应用
    jQuery 中 serialize() 方法会受到asp.net 页面影响
    javascript 对象转换 json 的插件
    MVC 4将jQuery升级到1.9出现各种问题。。。
    用MVC做可拖拽的留言板,利用 Jquery模板 JsRender
    未能加载文件或程序集“Microsoft.ReportViewer.WebForms, Version=8.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a”
    处理MVC中默认的Json方法返回时间的问题
    jQuery 中使用$.post 无法获取 json
    MVC中用 BundleCollection 压缩CSS时图片路径问题
    MVC中返回Json的几种声明方式
  • 原文地址:https://www.cnblogs.com/wangdongkai/p/5755144.html
Copyright © 2011-2022 走看看