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;
}
时间: 2024-12-18 04:02:43

3243 区间翻转的相关文章

WIKIOI 3243 区间翻转

3243 区间翻转 题目描述 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 Outp

UVA 11922 Splay区间翻转+分裂+合并

- Permutation Transformer Time Limit:2000MS     Memory Limit:0KB     64bit IO Format:%lld & %llu Submit Status Practice UVA 11922 Appoint description:  System Crawler  (2014-11-30) Description  Permutation Transformer  Write a program to transform th

区间翻转

时间限制: 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

HDU 3911 Black and White (线段树,区间翻转)

  [题目地址] vjudge HDU [题目大意] 海滩上有一堆石头. 石头的颜色是白色或黑色. 小肥羊拥有魔术刷,她可以改变连续石的颜色,从黑变白,从白变黑. 小肥羊非常喜欢黑色,因此她想知道范围[i,j]中连续的黑色石头的最长时间. 有多种情况,每种情况的第一行是整数n(1 <= n <= 10 ^ 5),后跟n个整数1或0(1表示黑石头,0表示白石头),然后是整数 M(1 <= M <= 10 ^ 5)后跟M个运算,格式为xij(x = 0或1),x = 1表示更改范围[i

HDU 1890 Splay区间翻转

D - Robotic Sort Time Limit:2000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 1890 Appoint description:  System Crawler  (2014-11-27) Description Somewhere deep in the Czech Technical University buildings, t

HDU3487(splay区间翻转+区间切割)

题意:开始有一个1,2,3,...n的序列,进行m次操作,cut a b c将区间[a,b]取出得到新序列,将区间插入到新序列第c个元素之后.filp a b 将区间a,b翻转,输出最终的序列. 思路:对于cut操作我们需要先提取出区间[a,b]然后,先暂时分裂出去,然后以c为边界分裂左右两部分,然后合并左边的和区间[a,b],将最大的旋转至根,然后和右边的合并.对于filp操作,我们可以使用lazy标记,先不翻转,需要的时候再翻转,代码如下 [cpp] view plaincopy /****

HihoCoder1677 : 翻转字符串(Splay)(区间翻转)

描述 给定一个字符串S,小Hi希望对S进行K次翻转操作. 每次翻转小Hi会指定两个整数Li和Ri,表示要将S[Li..Ri]进行翻转.(S下标从0开始,即S[0]是第一个字母) 例如对于S="abcdef",翻转S[2..3] 得到S="abdcef":再翻转S[0..5]得到S="fecdba". 输入 第一行包含一个由小写字母组成的字符串S. 第二行包含一个整数K. 以下K行每行包含两个整数Li和Ri. 对于50%的数据,1 ≤ |S| ≤

[平衡树-Splay]文艺平衡树_区间翻转

题意 给你一个1-n的排列,1,2,...n 求翻转k次之后的序列 例如:1,2,3,5,4 翻转2-4 -> 1,5,3,2,4 题解 首先,splay操作之后的中序遍历是不会发生变化的.初始序列无论splay多少次中序遍历不变 中序遍历有一个显而易见的性质,就是左子树和右子树交换之后,中序遍历也就翻转了. 题目中的翻转操作也可以通过某个点的左右子树交换 问题1:这个点的子树要锁定题目要求的区间里,即这个点的的子树要覆盖这个区间,这样才能通过左右子树交换解决问题 我们可以通过splay操作让这

11922 - Permutation Transformer (Splay区间翻转)

UVA 11922 - Permutation Transformer 题目链接 题意:给一个序列,每次操作选择(a,b),把(a,b)序列翻转之后加到末尾,求最终序列 思路:Splay的应用,多一个flip标记,在开头多一个虚拟的0结点,这样每次就利用Splay进行分裂合并即可 代码: #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include