题目描述 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 150000
using 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 30000
using 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]);
}
}