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|1
using 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;
}
原文地址:https://www.cnblogs.com/shenben/p/5904111.html