uva 11922 - Permutation Transformer

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

坑爹的BST,代码调得烦死,终于AC了第一道splay。

所谓的splay就是具有伸展功能的BST,其实一般的BST也可以伸展的,只要按照splay的三种旋转方式,将结点旋转到根即可。

这个伸展功能有什么用呢?显然根据BST的性质,左子树<根<右子树,那么想要将一颗splay分成两部分,只要将中间过渡值转到根,卸下右子树即可,要合并两颗splay,同样的将左边的最大值转到根,保证右子树为空,在接上右子树即可。

注意这里的小于并非只限于数值比较,这里应看成偏序关系,一般普通的BST按照数值大小来排列的树,往左右子树下的时候可以比较v,而这道题显然是根据个数来分的,因此伸展保持元素的相对位置不变,分裂、合并均应该按照元素个数来处理,这也是第k小的真正含义,是基于偏序关系的比较。

代码:

#include<cstdio>
#include<iostream>
#define Maxn 100010
using namespace std;

struct splay{
    splay* ch[2];
    int s;
    int flip;
    int v;
    splay(){s=0;}
    int cmp(int k)const{
        int d=k-ch[0]->s;
        if(d==1) return -1;
        return d<=0?0:1;
    }
    void maintain(){
        s=ch[0]->s+ch[1]->s+1;
    }
    void pushdown(){
        if(flip){
            flip=0;
            swap(ch[0],ch[1]);
            ch[0]->flip^=1;
            ch[1]->flip^=1;
        }
    }
}sp[Maxn];
splay* null=new splay();
void rotate(splay* &o,int d){
    splay* k=o->ch[d^1];o->ch[d^1]=k->ch[d];k->ch[d]=o;
    o->maintain();k->maintain();o=k;
}
void extend(splay* &o,int k){
    o->pushdown();
    int d=o->cmp(k);
    if(d==1) k-=o->ch[0]->s+1;
    if(d!=-1){
        splay* p=o->ch[d];
        p->pushdown();
        int d2=p->cmp(k);
        int k2=d2==0?k:k-p->ch[0]->s-1;
        if(d2!=-1){
            extend(p->ch[d2],k2);
            if(d==d2) rotate(o,d^1);
            else rotate(o->ch[d],d);
        }
        rotate(o,d^1);
    }
}
splay* merge(splay* left,splay* right){
    extend(left,left->s);
    left->ch[1]=right;
    left->maintain();
    return left;
}
void split(splay* o,int k,splay* &left,splay* &right){
    extend(o,k);
    left=o;
    right=o->ch[1];
    o->ch[1]=null;
    left->maintain();
}
splay* build(int n,int &sz){
    if(!n) return null;
    splay* l=build(n>>1,sz);
    splay* o=&sp[++sz];
    o->v=sz;
    o->flip=0;
    o->ch[0]=l;
    o->ch[1]=build((n-1)>>1,sz);
    o->maintain();
    return o;
}
void print(splay* o){
    if(o!=null){
        o->pushdown();
        print(o->ch[0]);
        if(o->v) printf("%d\n",o->v);
        print(o->ch[1]);
    }
}
int main()
{
    int n,m,l,r;
    while(~scanf("%d%d",&n,&m)){
        int sz=-1;
        splay* root=build(n+1,sz);
        splay *left,*mid,*right,*o;
        for(int i=0;i<m;i++){
            scanf("%d%d",&l,&r);
            split(root,l,left,o);
            split(o,r-l+1,mid,right);
            mid->flip^=1;
            root=merge(merge(left,right),mid);
        }
        print(root);
    }
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值