• 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;
    }
  • 相关阅读:
    了解语言学习的四个阶段,孩子的英语学习更从容
    MySQL 修改字段类型或长度
    js中退出语句break,continue和return 比较
    PHP中unset,array_splice删除数组中元素的区别
    php判断一个数组是另一个数组的子集
    PHP实现一维数组转二维数组的方法
    基于 HTML5 WebGL 的 3D 网络拓扑图
    SQL 2008下载地址以及全新安装详细过程
    php从数组中取出一段 之 array_slice
    Linux命令:cp (copy)复制文件或目录
  • 原文地址:https://www.cnblogs.com/shenben/p/5904111.html
Copyright © 2020-2023  润新知