UVA 11922 Permutation Transformer Splay

来源:互联网 发布:chrome淘宝秒杀插件 编辑:程序博客网 时间:2024/04/28 15:23

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 22 54 8

Sample Output

16732451098




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

对区间[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;}




原创粉丝点击