code vs 3243 区间反转(线段树)

来源:互联网 发布:android 防止sql注入 编辑:程序博客网 时间:2024/06/06 07:35

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


题解:线段树。

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

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 150000using namespace std;int lx[N*4],rx[N*4],rev[N*4];int pos[N*4],n,m,a[N];void build(int now,int l,int r){if (l==r){pos[now]=l;return ;}int mid=(l+r)/2;build(now<<1,l,mid);  lx[now]=now<<1;build(now<<1|1,mid+1,r); rx[now]=now<<1|1;}void pushdown(int now){if (rev[now]){  rev[now]=0;  rev[lx[now]]^=1;  rev[rx[now]]^=1;  swap(lx[now],rx[now]);    }}void change(int now,int l,int r,int ll,int rr){if (l==ll&&r==rr) { rev[now]^=1; return; }pushdown(now);int mid=(l+r)/2;if (ll<=mid)  change(lx[now],l,mid,ll,rr);if (rr>mid) change(rx[now],mid+1,r,ll,rr);}int find(int now,int l,int r,int x){if (l==r) return pos[now];int mid=(l+r)/2;pushdown(now);if (x<=mid)  find(lx[now],l,mid,x);    else find(rx[now],mid+1,r,x);}int main(){freopen("a.in","r",stdin);scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&a[i]);build(1,1,n);scanf("%d",&m);for (int i=1;i<=m;i++){int x,y; scanf("%d%d",&x,&y);change(1,1,n,x,y);}for (int i=1;i<=n;i++) { int t=find(1,1,n,i); printf("%d ",a[t]); }printf("\n");}

这道题可以用块状链表过6个点,可以用来练习反转操作

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#include<cmath>#include<queue>#define N 30000using namespace  std;int n,m,b[N],blocksize,st[N];struct data{int size,rev,next;    int s[1003]; }a[N];queue<int> p;void clear(int now){a[now].size=0;a[now].rev=0;a[now].next=0;}int newnode(){int temp=p.front(); p.pop();return temp;}void pushdown(int now){if (a[now].rev){int k=a[now].size;for (int i=1;i<=k;i++) b[k-i+1]=a[now].s[i];for (int i=1;i<=k;i++) a[now].s[i]=b[i];a[now].rev=0;}}void del(int now){clear(now);p.push(now);}void merge(int now){int t=a[now].next;pushdown(now); pushdown(t);for (int i=1;i<=a[t].size;i++) a[now].s[++a[now].size]=a[t].s[i];a[now].next=a[t].next;del(t);}void maintain(int now){for (;now!=-1;now=a[now].next) if (a[now].next!=-1&&a[now].size+a[a[now].next].size<=blocksize)  merge(now);}void init(){for (int i=1;i<=N;i++)  p.push(i);a[0].next=-1; a[0].size=0;}void find(int &now,int &pos)  {      for (now=0;a[now].next!=-1&&pos>a[now].size;now=a[now].next)        pos-=a[now].size;}  void spilt(int now,int pos)  {      pushdown(now);       int t=newnode();    if (a[now].size)    for (int i=pos;i<=a[now].size;i++)       a[t].s[++a[t].size]=a[now].s[i];      a[t].next=a[now].next;       a[now].next=t; a[now].size=max(pos-1,0); }  void insert(int x,int pos){int now; find(now,pos);//cout<<now<<" "<<pos<<" "<<a[now].size<<endl;spilt(now,pos);a[now].s[++a[now].size]=x;maintain(now);}void solve(int x,int y,int &l,int &r){int pos=x;find(l,pos); //cout<<l<<" "<<a[l].size<<endl;spilt(l,pos);pos=y+1; find(r,pos);  //cout<<r<<" "<<a[r].size<<endl;spilt(r,pos);pos=y; find(r,pos);}void reserve(int x,int y){int l,r;solve(x,y,l,r);//cout<<l<<" "<<r<<endl;int now=l;int top=0;for (int i=a[l].next;i!=a[r].next;i=a[i].next) st[++top]=i,a[i].rev^=1;a[st[1]].next=a[r].next;for (int i=top;i>=2;i--) a[st[i]].next=st[i-1];a[l].next=r;maintain(l);}int main(){ scanf("%d",&n); init(); blocksize=sqrt(n); for (int i=1;i<=n;i++)    {    int x; scanf("%d",&x);    insert(x,i);}scanf("%d",&m);for (int i=1;i<=m;i++){int x,y;scanf("%d%d",&x,&y);reserve(x,y);}for (int now=0;now!=-1;now=a[now].next) pushdown(now);for (int now=0;now!=-1;now=a[now].next) { for (int i=1;i<=a[now].size;i++)  printf("%d ",a[now].s[i]); }}






0 0
原创粉丝点击