zoukankan      html  css  js  c++  java
  • POJ 3580

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

    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

    题意:

    给出五种操作:

    1. ADD x y D: 对区间[x,y]全部加上D;
    2. REVERSE x y: 反转区间[x,y];
    3. REVOLVE x y T: 将区间[x,y]向右循环平移T次,每次一格,例如 REVOLVE 2 4 2 在{1, 2, 3, 4, 5}操作结果为{1, 3, 4, 2, 5};
    4. INSERT x P: 在位置x后面插入一个数P;
    5. DELETE x: 删除位置x上的数;
    6. MIN x y: 求区间[x,y]中的最小值;

    题解:

    splay模板题,lazy标记模仿线段树标记区间加上多少,rev标记标记是否需要反转,mini[x]记录节点x统领的整棵子树(包含自己)的key[x]的最小值。

    AC代码:

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int maxn=2e5+10;
    int n,m;
    int a[maxn];
    
    /******************************** splay - st ********************************/
    #define Key_value ch[ch[root][1]][0]
    int root,nodecnt;
    int par[maxn],ch[maxn][2];
    int key[maxn],mini[maxn],size[maxn];
    int lazy[maxn]; //lazy标记
    bool rev[maxn]; //反转标记
    int pool[maxn],poolsize; //节点回收
    void NewNode(int &x,int p,int k)
    {
        if(poolsize>0) x=pool[--poolsize];
        else x=++nodecnt;
        par[x]=p;
        ch[x][0]=ch[x][1]=0;
        key[x]=k;
        mini[x]=k;
        size[x]=1;
        lazy[x]=0;
        rev[x]=0;
    }
    void Update_Rev(int x)
    {
        if(x==0) return;
        swap(ch[x][0],ch[x][1]);
        rev[x]^=1;
    }
    void Update_Add(int x,int val)
    {
        if(x==0) return;
        key[x]+=val;
        mini[x]+=val;
        lazy[x]+=val;
    }
    void Pushup(int x)
    {
        size[x]=size[ch[x][0]]+size[ch[x][1]]+1;
    
        mini[x]=key[x];
        if(ch[x][0]) mini[x]=min(mini[x],mini[ch[x][0]]);
        if(ch[x][1]) mini[x]=min(mini[x],mini[ch[x][1]]);
    }
    void Pushdown(int x)
    {
        if(rev[x])
        {
            Update_Rev(ch[x][0]);
            Update_Rev(ch[x][1]);
            rev[x]=0;
        }
        if(lazy[x])
        {
            Update_Add(ch[x][0],lazy[x]);
            Update_Add(ch[x][1],lazy[x]);
            lazy[x]=0;
        }
    }
    void Inorder(int x) //debug
    {
        if(x==0) return;
        Pushdown(x);
        Inorder(ch[x][0]);
        printf("%d ",key[x]);
        Inorder(ch[x][1]);
        Pushup(x);
        if(x==root) printf("
    ");
    }
    void Rotate(int x,int type) //旋转,0为左旋zag,1为右旋zig
    {
        int y=par[x];
        Pushdown(y); Pushdown(x); //先把y的标记向下传递,再把x的标记往下传递
        ch[y][!type]=ch[x][type]; par[ch[x][type]]=y;
        if(par[y]) ch[par[y]][(ch[par[y]][1]==y)]=x;
        par[x]=par[y];
        ch[x][type]=y; par[y]=x;
        Pushup(y); Pushup(x);
    }
    void Splay(int x,int goal)
    {
        while(par[x]!=goal)
        {
            if(par[par[x]]==goal) Rotate(x,ch[par[x]][0]==x); //左孩子zig,右孩子zag
            else
            {
                Pushdown(par[par[x]]); Pushdown(par[x]); Pushdown(x);
                int y=par[x];
                int type=(ch[par[y]][0]==y); //type=0,y是右孩子;type=1,y是左孩子
                if(ch[y][type]==x)
                {
                    Rotate(x,!type);
                    Rotate(x,type);
                }
                else
                {
                    Rotate(y,type);
                    Rotate(x,type);
                }
            }
        }
        if(goal==0) root=x;
    }
    int Get_Kth(int x,int k) //得到第k个节点
    {
        Pushdown(x);
        int t=size[ch[x][0]]+1;
        if(t==k) return x;
        if(t>k) return Get_Kth(ch[x][0],k);
        else return Get_Kth(ch[x][1],k-t);
    }
    int Get_Min(int x)
    {
        Pushdown(x);
        while(ch[x][0])
        {
            x=ch[x][0];
            Pushdown(x);
        }
        return x;
    }
    int Get_Max(int x)
    {
        Pushdown(x);
        while(ch[x][1])
        {
            x=ch[x][1];
            Pushdown(x);
        }
        return x;
    }
    void Build(int &x,int l,int r,int par) //建树,先建立中间结点,再建两端的方法
    {
        if(l>r) return;
        int mid=(l+r)/2;
        NewNode(x,par,a[mid]);
        Build(ch[x][0],l,mid-1,x);
        Build(ch[x][1],mid+1,r,x);
        Pushup(x);
    }
    void Init() //初始化,前后各加一个空节点
    {
        root=nodecnt=poolsize=0;
        par[root]=ch[root][0]=ch[root][1]=0;
        key[root]=size[root]=0;
        lazy[root]=rev[root]=0;
        NewNode(root,0,-1); //头部加入一个空位
        NewNode(ch[root][1],root,-1); //尾部加入一个空位
        Build(Key_value,1,n,ch[root][1]);
        Pushup(ch[root][1]);
        Pushup(root);
    }
    void Add(int l,int r,int val)
    {
        Splay(Get_Kth(root,l-1+1),0); //l的前驱l-1伸展到根
        Splay(Get_Kth(root,r+1+1),root); //r的后继r+1伸展到根的右孩子
        Update_Add(Key_value,val);
        Pushup(ch[root][1]);
        Pushup(root);
    }
    void Move(int l,int r,int p) //截取[l,r]放到位置p之后
    {
        Splay(Get_Kth(root,l-1+1),0); //l的前驱l-1伸展到根
        Splay(Get_Kth(root,r+1+1),root); //r的后继r+1伸展到根的右孩子
        int tmp=Key_value; //Key_value=ch[ch[root][1]][0]所统领的子树即[l,r]
        Key_value=0; //剥离[l,r]子树
        Pushup(ch[root][1]); Pushup(root);
        Splay(Get_Kth(root,p+0+1),0); //p伸展到根
        Splay(Get_Kth(root,p+1+1),root); //p的后继p+1伸展到根的右孩子
        Key_value=tmp; par[Key_value]=ch[root][1]; //接上[l,r]子树
        Pushup(ch[root][1]); Pushup(root);
    }
    void Reverse(int l,int r) //反转[l,r]区间
    {
        Splay(Get_Kth(root,l-1+1),0);
        Splay(Get_Kth(root,r+1+1),root);
        Update_Rev(Key_value);
        Pushup(ch[root][1]);
        Pushup(root);
    }
    void Revolve(int l,int r,int T)
    {
        int D=r-l+1;
        int L=T%D;
        if(L==0) return;
        Move(r-L+1,r,l-1);
    }
    void Insert(int p,int k)
    {
        Splay(Get_Kth(root,p+0+1),0); //p伸展到根
        Splay(Get_Kth(root,p+1+1),root); //p的后继p+1伸展到根的右孩子
        Inorder(Key_value);
        NewNode(Key_value,ch[root][1],k);
        Pushup(ch[root][1]); Pushup(root);
    }
    void Collect(int x) //回收节点x统领的子树
    {
        if(x==0) return;
        pool[poolsize++]=x;
        Collect(ch[x][0]);
        Collect(ch[x][1]);
    }
    void Delete(int p)
    {
        Splay(Get_Kth(root,p-1+1),0); //p的前驱p-1伸展到根
        Splay(Get_Kth(root,p+1+1),root); //p的后继p+1伸展到根的右孩子
        Collect(Key_value);
        par[Key_value]=0;
        Key_value=0;
        Pushup(ch[root][1]); Pushup(root);
    }
    int Min(int l,int r)
    {
        Splay(Get_Kth(root,l-1+1),0);
        Splay(Get_Kth(root,r+1+1),root);
        return mini[Key_value];
    }
    /******************************** splay - ed ********************************/
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d",&a[i]);
        Init();
    
        scanf("%d",&m);
        char op[50];
        for(int i=1;i<=m;i++)
        {
            scanf("%s",op);
            if(op[0]=='A')
            {
                int x,y,D; scanf("%d%d%d",&x,&y,&D);
                Add(x,y,D);
            }
            if(op[0]=='R' && op[3]=='E')
            {
                int x,y; scanf("%d%d",&x,&y);
                Reverse(x,y);
            }
            if(op[0]=='R' && op[3]=='O')
            {
                int x,y,T; scanf("%d%d%d",&x,&y,&T);
                Revolve(x,y,T);
            }
            if(op[0]=='I')
            {
                int x,p; scanf("%d%d",&x,&p);
                Insert(x,p);
            }
            if(op[0]=='D')
            {
                int x; scanf("%d",&x);
                Delete(x);
            }
            if(op[0]=='M')
            {
                int x,y; scanf("%d%d",&x,&y);
                printf("%d
    ",Min(x,y));
            }
            //Inorder(root);
        }
    }

    两组数据:

    5
    1 2 3 4 5 11
    ADD 1 4 1
    REVERSE 2 4
    ADD 2 5 2
    REVOLVE 2 4 2
    DELETE 4
    MIN 1 3
    REVERSE 1 4
    INSERT 2 4
    REVOLVE 1 4 6
    DELETE 2
    MIN 1 4
    10
    1 2 3 4 5 6 7 8 9 10
    15
    ADD 4 8 3
    MIN 5 7
    MIN 7 10
    REVERSE 2 5
    MIN 2 6
    MIN 2 3
    INSERT 3 4
    MIN 3 4
    MIN 5 10
    DELETE 6
    MIN 3 5
    MIN 4 4
    REVOLVE 3 6 7
    MIN 5 8
    MIN 7 10

    第一次写完之后一些BUG通过第一组数据调完了,感觉应该没问题了,然后交了发现WA,

    然后用第二组数据一测,发现居然是因为用来debug的一些输出忘记删掉了……尴尬……

  • 相关阅读:
    part11-1 Python图形界面编程(Python GUI库介绍、Tkinter 组件介绍、布局管理器、事件处理)
    part10-3 Python常见模块(正则表达式)
    Cyclic Nacklace HDU
    模拟题 Right turn SCU
    状态DP Doing Homework HDU
    Dp Milking Time POJ
    区间DP Treats for the Cows POJ
    DP Help Jimmy POJ
    Dales and Hills Gym
    Kids and Prizes Gym
  • 原文地址:https://www.cnblogs.com/dilthey/p/9404613.html
Copyright © 2011-2022 走看看