一、题目
二、解法
最近学了无旋
treap
\text{treap}
treap,那就用它来水一发吧。
反转区间我们不考虑权值,一开始直接用
merge
\text{merge}
merge插入,修改时直接
split
\text{split}
split出三个区间
[
1
,
l
−
1
]
,
[
l
,
r
]
,
[
r
+
1
,
n
]
[1,l-1],[l,r],[r+1,n]
[1,l−1],[l,r],[r+1,n],对第二个区间打标记,然后暴力
merge
\text{merge}
merge即可。
这里用到了
treap
\text{treap}
treap打懒标记的思想,在
split,merge
\text{split,merge}
split,merge时都下传标记,因为我们不考虑权值,所以我们下传时直接交换左右儿子,最后答案时平衡树的中序便利。
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <ctime>
using namespace std;
const int MAXN = 100005;
int read()
{
int x=0,flag=1;char c;
while((c=getchar())<'0' || c>'9') if(c=='-') flag=-1;
while(c>='0' && c<='9') x=(x<<3)+(x<<1)+(c^48),c=getchar();
return x*flag;
}
int n,m,rt;
int ch[MAXN][2],siz[MAXN],hp[MAXN],fl[MAXN];
struct node
{
int r[2];
node() {r[0]=r[1]=0;}
}emp;
void up(int x)
{
siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
void down(int x)
{
fl[ch[x][0]]^=1;fl[ch[x][1]]^=1;
swap(ch[x][0],ch[x][1]);
fl[x]=0;
}
node split(int x,int s)
{
if(!x) return emp;
if(fl[x]) down(x);
node y;
if(siz[ch[x][0]]>=s)
{
y=split(ch[x][0],s);
ch[x][0]=y.r[1];
y.r[1]=x;
}
else
{
y=split(ch[x][1],s-siz[ch[x][0]]-1);
ch[x][1]=y.r[0];
y.r[0]=x;
}
up(x);
return y;
}
int merge(int x,int y)
{
if(!x || !y) return x+y;
if(hp[x]<hp[y])
{
if(fl[x]) down(x);
ch[x][1]=merge(ch[x][1],y);
up(x);
return x;
}
if(fl[y]) down(y);
ch[y][0]=merge(x,ch[y][0]);
up(y);
return y;
}
void print(int x)
{
if(!x) return ;
if(fl[x]) down(x);
print(ch[x][0]);printf("%d ",x);print(ch[x][1]);
}
int main()
{
srand(time(0));
n=read();m=read();
for(int i=1;i<=n;i++)
{
siz[i]=1;hp[i]=rand();
rt=merge(rt,i);
}
for(int i=1;i<=m;i++)
{
int l=read(),r=read();
node x=split(rt,l-1),y=split(x.r[1],r-l+1);
fl[y.r[0]]^=1;
rt=merge(x.r[0],merge(y.r[0],y.r[1]));
}
print(rt);
}