首页 > 代码库 > 3243 区间翻转

3243 区间翻转

3243 区间翻转

 

 时间限制: 1 s
 空间限制: 256000 KB
 题目等级 : 钻石 Diamond
 
 
 
题目描述 Description

给出N个数,要求做M次区间翻转(如1 2 3 4变成4 3 2 1),求出最后的序列

输入描述 Input Description

第一行一个数N,下一行N个数表示原始序列,在下一行一个数M表示M次翻转,之后的M行每行两个数L,R表示将区间[L,R]翻转。

输出描述 Output Description

一行N个数 , 表示最终序列。

样例输入 Sample Input

4

1 2 3 4

2

1 2

3 4

样例输出 Sample Output

2 1 4 3

数据范围及提示 Data Size & Hint

对于30%的数据满足n<=100 , m <= 10000

对于100%的数据满足n <= 150000 , m <= 150000

对于100%的数据满足n为2的幂,且L = i * 2^j + 1 , R = (i + 1) * 2^j

分类标签 Tags 点此展开 

 
线段树 树结构

 

题解:

splay~~~

因为题目中L = i * 2^j + 1 , R = (i + 1) * 2^j的限制,所以给出的反转区间必然是线段树中一个整块,那么我们可以利用这个性质,每次对于需要反转的区间打反转标记,对于线段树中的每一个节点记录他的左右儿子,标记下放的时候,就交换左右儿子,查找的时候<=mid就跳转到左儿子,否则跳转到右儿子。

这样的话就可以直接用线段树来搞,区间打标记然后交换左右儿子就可以了。

AC代码:

跑过全网

技术分享

#include<cstdio>#include<algorithm>#define lc k<<1#define rc k<<1|1using namespace std;inline const int read(){    register int x=0,f=1;    register char ch=getchar();    while(ch>9||ch<0){if(ch==-)f=-1;ch=getchar();}    while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}    return x*f;}const int M=2e5+10;const int N=M<<2;int ls[N],rs[N],rev[N],pos[N],a[M];inline void build(int k,int l,int r){    if(l==r){        pos[k]=l;return ;//只记录下标,自行脑补     }    int mid=l+r>>1;    ls[k]=lc;rs[k]=rc;    build(ls[k],l,mid);    build(rs[k],mid+1,r);}inline void pushdown(int k){    if(!rev[k]) return ;    rev[k]=0;    rev[ls[k]]^=1;    rev[rs[k]]^=1;    swap(ls[k],rs[k]);}inline void change(int k,int l,int r,int x,int y){    if(l==x&&r==y){        rev[k]^=1;return ;    }    pushdown(k);    int mid=l+r>>1;    if(y<=mid) change(ls[k],l,mid,x,y);    else if(x>mid) change(rs[k],mid+1,r,x,y);    else change(ls[k],l,mid,x,mid),change(rs[k],mid+1,r,mid+1,y);}inline int query(int k,int l,int r,int p){    if(l==r) return pos[k];    pushdown(k);    int mid=l+r>>1;    if(p<=mid) query(ls[k],l,mid,p);    else query(rs[k],mid+1,r,p);}int main(){    int n=read();    for(int i=1;i<=n;i++) a[i]=read();    build(1,1,n);    int m=read();    for(int i=1,x,y;i<=m;i++) x=read(),y=read(),change(1,1,n,x,y);//使得根结点右孩子为左子树    for(int i=1,t;i<=n;i++) t=query(1,1,n,i),printf("%d ",a[t]);    return 0;}

 

3243 区间翻转