Permutation Transformer+uva+splay树

Time Limit: 2000MS Memory Limit: Unknown 64bit IO Format: %lld & %llu

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
 
  
解决方案:数列的拆分与合并可用splay树来模拟,翻转可根据之前线段树的经验,用一个标记来完成,写了个filp标记和push_down函数
code:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
using namespace std;
struct node
{
    node *ch[2];
    int v;
    int s;
    int flip;
    int cmp(int k)const
    {
        int d=k - ch[0]->s;
        if(d==1) return -1;
        return d<=0?0:1;
    }///比较函数
    void pushdown()
    {
        if(flip)
        {
            flip=0;
            swap(ch[0],ch[1]);
            ch[0]->flip=!ch[0]->flip;
            ch[1]->flip=!ch[1]->flip;
        }
    }///翻转函数
    void maintian()
    {
        s=ch[0]->s+ch[1]->s+1;
    }///统计子孙函数


};
node *null=new node();
void rotate(node * &rt,int d)
{
    node *k=rt->ch[d^1];
    rt->ch[d^1]=k->ch[d];
    k->ch[d]=rt;
    rt->maintian();
    k->maintian();
    rt=k;
}///翻滚函数
void splay(node * &rt,int k)
{
    rt->pushdown();
    int d=rt->cmp(k);
    if(d==1) k-=rt->ch[0]->s+1;
    if(d!=-1)
    {
        node *p=rt->ch[d];
        p->pushdown();
        int d2=p->cmp(k);
        int k2=(d2==0?k:k-p->ch[0]->s-1);
        if(d2!=-1)
        {
            splay(p->ch[d2],k2);
            if(d==d2) rotate(rt,d^1);
            else rotate(rt->ch[d],d);
        }
        rotate(rt,d^1);
    }
}///伸展函数
node * merge(node *left,node *right)
{
    splay(left,left->s);
    left->ch[1]=right;
    left->maintian();
    return left;

}///合并
void split(node * rt,int k,node * & left,node * & right)
{
    splay(rt,k);
    left=rt;
    right=rt->ch[1];
    rt->ch[1]=null;
    left->maintian();
}///拆分

const int maxn=101000;
struct splayqueue
{

    int n;
    node seq[maxn];
    node *root;
    node *build(int sz)
    {
        if(!sz) return null;
        node *L=build(sz/2);
        node *rt=&seq[++n];
        rt->v=n;
        rt->ch[0]=L;
        rt->ch[1]=build(sz-sz/2-1);
        rt->flip=rt->s=0;
        rt->maintian();
        return rt;
    }
    void init(int sz)
    {
        null->s=0;
        n=0;
        root=build(sz);
    }


};
vector<int>V;
void print(node *rt){

   if(rt!=null){
    rt->pushdown();
    print(rt->ch[0]);
    V.push_back(rt->v);
    print(rt->ch[1]);
   }
}
splayqueue ss;
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    V.clear();
    ss.init(n+1);
 //   cout<<"sd";
    while(m--){
        int a,b;
        scanf("%d%d",&a,&b);
        node *left,*mid,*right,*rt;
        split(ss.root,a,left,rt);///最左那个点事虚拟节点
        split(rt,b-a+1,mid,right);
        mid->flip^=1;
        ss.root=merge(merge(left,right),mid);
    }
    print(ss.root);
    for(int i=1;i<V.size();i++){
       printf("%d\n",V[i]-1);
    }
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值