UVA 11922 Permutation Transformer Splay

Description

Download as PDF


  Permutation Transformer 

Write a program to transform the permutation 1, 2, 3,..., n according to m instructions. Each instruction (ab) means to take out the subsequence from the a-th to the b-th element, reverse it, then append it to the end.

Input

There is only one case for this problem. The first line contains two integers n and m ( 1$ le$nm$ le$100, 000). Each of the next m lines contains an instruction consisting of two integers a and b ( 1$ le$a$ le$b$ le$n).

Output

Print n lines, one for each integer, the final permutation.


Explanation of the sample below

Instruction (2,5): Take out the subsequence {2,3,4,5}, reverse it to {5,4,3,2}, append it to the remaining permutation {1,6,7,8,9,10}

Instruction (4,8): The subsequence from the 4-th to the 8-th element of {1,6,7,8,9,10,5,4,3,2} is {8,9,10,5,4}. Take it out, reverse it, and you'll get the sample output.


Warning: Don't use cincout for this problem, use faster i/o methods e.g scanfprintf.

Sample Input

10 2
2 5
4 8

Sample Output

1
6
7
3
2
4
5
10
9
8




-----------------

对区间[1,n]执行m条指令。

指令[a,b]表示取出第a~b元素翻转并放入队列尾部。

Splay的构造参考《运用伸展树解决数列维护问题》

具体代码的编写参考了NOI 2005 维护数列-BYVoid

-----------------

/**
    Splay Tree 索引
    Node:
        void addIt(int ad) 区间添加ad
        void revIt() 区间翻转
        void upd() 更新结点,子树改变后使用
        void pushdown() 向下传递懒惰标记
    Splay:
        Node* newNode(int v,Node* f) 构造一个val值为v的节点,父节点为f,
        Node* build(int l,int r,Node* f) 构造区间[l,r],父节点为f;
        void rotate(Node* t,int d) 左旋右旋
        void splay(Node* t,Node* f) 将结点t伸展到f
        void select(int k) 返回第k个节点并伸展到f,不计虚拟结点
        Node*&get(int l, int r) 返回区间[l,r],即l-1旋转到根,r+1旋转到根的右儿子
        void reverse(int l,int r) 翻转区间[l,r]
        void split(int l,int r,Node*&s1) 将区间[l,r]剪切到s1
        void cut(int l,int r) 将区间[l,r]剪切到序列尾部
        void init(int n) 构造区间[1,n]并初始化
        void show(Node* rt) 输出树rt的中序遍历,debug用
        void output(int l,int r) 输出并伸展区间[l,r],复杂度较高待优化
**/
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <vector>

using namespace std;
const int MAX_N = 150000 + 10;
const int INF = ~0U >> 1;
struct Node{
    Node *ch[2],*pre;//左右子树,父节点
    int val;//关键字
    int size;//以它为根的子树的总结点数
    int mx;//最大值
    int add;//添加标记
    bool rev;//翻转标记
    Node(){
        size=0;
        val=mx=-INF;
        add=0;
    }
    void addIt(int ad){
        add+=ad;
        mx+=ad;
        val+=ad;
    }
    void revIt(){
        rev^=1;
    }
    void upd(){
        size=ch[0]->size+ch[1]->size+1;
        mx=max(val,max(ch[0]->mx,ch[1]->mx));
    }
    void pushdown();
}Tnull,*null=&Tnull;
void Node::pushdown(){
    if (add!=0){
        for (int i=0;i<2;++i)
            if (ch[i]!=null) ch[i]->addIt(add);
        add = 0;
    }
    if (rev){
        swap(ch[0],ch[1]);
        for (int i=0;i<2;i++)
            if (ch[i]!=null) ch[i]->revIt();
        rev = 0;
    }
}
struct Splay{
    Node nodePool[MAX_N],*cur;//内存分配
    Node* root;//根
    Splay(){
        cur=nodePool;
        root=null;
    }
    //清空内存,init()调用
    void clear(){
        cur=nodePool;
        root=null;
    }
    //新建节点,build()用
    Node* newNode(int v,Node* f){
        cur->ch[0]=cur->ch[1]=null;
        cur->size=1;
        cur->val=v;
        cur->mx=v;
        cur->add=0;
        cur->rev=0;
        cur->pre=f;
        return cur++;
    }
    //构造区间[l,r]中点m,init()使用
    Node* build(int l,int r,Node* f){
        if(l>r) return null;
        int m=(l+r)>>1;
        Node* t=newNode(m,f);
        t->ch[0]=build(l,m-1,t);
        t->ch[1]=build(m+1,r,t);
        t->upd();
        return t;
    }
    //旋转操作,c=0表示左旋,c=1表示右旋
    void rotate(Node* x,int c){
        Node* y=x->pre;
        y->pushdown();
        x->pushdown();
        //先将y结点的标记向下传递(因为y在上面)
        y->ch[!c]=x->ch[c];
        if (x->ch[c]!=null) x->ch[c]->pre=y;
        x->pre=y->pre;
        if (y->pre!=null)
        {
            if (y->pre->ch[0]==y) y->pre->ch[0]=x;
            else y->pre->ch[1]=x;
        }
        x->ch[c]=y;
        y->pre=x;
        y->upd();//维护y结点
        if (y==root) root=x;
    }
    //Splay操作,表示把结点x转到结点f的下面
    void splay(Node* x,Node* f){
        x->pushdown();//下传x的标记
        while (x->pre!=f){
            if (x->pre->pre==f){//父节点的父亲为f,执行单旋
                if (x->pre->ch[0]==x) rotate(x,1);
                else rotate(x,0);
            }else{
                Node *y=x->pre,*z=y->pre;
                if (z->ch[0]==y){
                    if (y->ch[0]==x) rotate(y,1),rotate(x,1);//一字型旋转
                    else rotate(x,0),rotate(x,1);//之字形旋转
                }else{
                    if (y->ch[1]==x) rotate(y,0),rotate(x,0);//一字型旋转
                    else rotate(x,1),rotate(x,0);//之字形旋转
                }
            }
        }
        x->upd();//最后再维护X结点
    }
    //找到处在中序遍历第k个结点,并将其旋转到结点f的下面
    void select(int k,Node* f){
        int tmp;
        Node* x=root;
        x->pushdown();
        k++;//空出虚拟节点
        for(;;){
            x->pushdown();
            tmp=x->ch[0]->size;
            if (k==tmp+1) break;
            if (k<=tmp) x=x->ch[0];
            else{
                k-=tmp+1;
                x=x->ch[1];
            }
        }
        splay(x,f);
    }
    //选择[l,r]
    Node*&get(int l, int r){
        select(l-1,null);
        select(r+1,root);
        return root->ch[1]->ch[0];
    }
    //翻转[l,r]
    void reverse(int l,int r){
        Node* o=get(l,r);
        o->rev^=1;
        splay(o,null);
    }
    //剪切出[l,r]到s1
    void split(int l,int r,Node*&s1)
    {
        Node* tmp=get(l,r);
        root->ch[1]->ch[0]=null;
        root->ch[1]->upd();
        root->upd();
        s1=tmp;
    }
    void cut(int l,int r)
    {
        Node* tmp;
        split(l,r,tmp);
        select(root->size-1,null);
        select(root->size-2,root);
        root->ch[0]->ch[1]=tmp;
        tmp->pre=root->ch[0];
        root->ch[0]->upd();
        root->upd();
    }
    //初始化
    void init(int n){
        clear();
        root=newNode(0,null);
        root->ch[1]=newNode(n+1,root);
        root->ch[1]->ch[0]=build(1,n,root->ch[1]);
        root->upd();
    }
    //输出中序遍历,debug用
    void show(Node* rt){
        if (rt==null) return;
        if (rt->ch[0]!=null) show(rt->ch[0]);
        cerr<<"rt="<<rt->val;
        if (rt->ch[0]!=null) cerr<<" l="<<rt->ch[0]->val;
        if (rt->ch[1]!=null) cerr<<" r="<<rt->ch[1]->val;
        if (rt->pre  !=null) cerr<<" pre="<<rt->pre->val;
        cerr<<endl;
        if (rt->ch[1]!=null) show(rt->ch[1]);
    }
    //按序输出
    void output(int l,int r){
        for (int i=l;i<=r;i++){
            select(i,null);
            cout<<root->val<<endl;
        }
        //cout<<endl;
    }

}T;
int main()
{
    int n,m,a,b;
    while (~scanf("%d%d",&n,&m))
    {
        T.init(n);
        while (m--)
        {
            scanf("%d%d",&a,&b);
            if (b<a) swap(a,b);
            T.reverse(a,b);
            T.cut(a,b);
        }
        T.output(1,n);
    }
    return 0;
}




原文地址:https://www.cnblogs.com/cyendra/p/3681593.html