这题两种主流的做法:
1.线段树合并。复杂度mlogn
2.二分+01线段树mlognlogn
主要讲第一种吧。第一种更快。这里我们要巧妙地运用线段树的合并和分裂,一开始全都是只有一个叶子的n棵线段树,假如l到r需要排序,就把l到r合并了,讲升序和降序记录在左端点l。用set维护树根,一开始set里面有n个树根1~n,以及一个虚根n+1。树set[i]维护的区间set[i]~set[i+1]-1的信息
假如set里面是 1 2 5 6 (n=5,6是虚根)
那么就维护了三棵树1 2 5 分别维护 区间1~1,2~4,5~5的信息
最开始set里面是 1 2 3 4 5 6 分别维护区间1~1,2~2,,,,5~5的信息
假如有个操作是 0 2 4 把2~4升序排序
我们就暴力把3~4这些树合并到2上面 然后在2位置标记是升序还是降序 并且在set中删除根3 4
就变成了 1 2 5 6
假如下一个操作是 1 3 4 显然在上一步我们把3~4并到2了 我们要用lower_bound去找到2 然后从2这棵树中把3,4分裂出来,由于2出的标记是升序(上一次操作标记的) 于是我们就把较大的两个数 分出去就行了 反之如果是降序标记 我们把较小的两个数分出去就行
#include<bits/stdc++.h>
using namespace std;
#define R register int
#define mid (l+r>>1)
#define il inline
typedef set<int>::iterator IT;
int n,m;
const int N = 1e5+10,M = 5e6+10;
il int read(){
int w=0,x=0;char c=0;
while(c>'9'||c<'0') w|=c=='-',c=getchar();
while(c<='9'&&c>='0') x=(x<<1)+(x<<3)+(c^48),c=getchar();
return w?-x:x;
}
int ls[M],rs[M],s[M],tot,op[N],rt[N],mem[M],ct;
set<int>srt;
il int newnode(){
return ct?mem[ct--]:++tot;
}
il void del(R x){
mem[++ct]=x;s[x]=ls[x]=rs[x]=0;
}
void update(R &x,R l,R r,R pos){
if(!x) x=newnode();s[x]=1;
if(l==r) return;
if(pos<=mid) update(ls[x],l,mid,pos);
else update(rs[x],mid+1,r,pos);
}
int merge(R x,R y){
if(!x||!y) return x+y;
s[x]+=s[y];
ls[x]=merge(ls[x],ls[y]);
rs[x]=merge(rs[x],rs[y]);
del(y);
return x;
}
int query(R x,R l,R r){
if(l==r) return l;
if(ls[x]) return query(ls[x],l,mid);
else return query(rs[x],mid+1,r);
}
void split(R x,R &y,R k,R op){
if(s[x]==k) return;
s[y=newnode()]=s[x]-k,s[x]=k;
if(op){
if(k<=s[rs[x]]) split(rs[x],rs[y],k,op),swap(ls[x],ls[y]);
else split(ls[x],ls[y],k-s[rs[x]],op);
}else{
if(k<=s[ls[x]]) split(ls[x],ls[y],k,op),swap(rs[x],rs[y]);
else split(rs[x],rs[y],k-s[ls[x]],op);
}
}
il IT spl(R x){
IT w = srt.lower_bound(x);
if(*w==x) return w;
--w;split(rt[*w],rt[x],x-*w,op[x]=op[*w]);
return srt.insert(x).first;
}
int main(){
n=read(),m=read();
srt.insert(n+1);
for(R i = 1; i <= n; i++){
R g;
g=read();
update(rt[i],1,n,g);
srt.insert(i);
}
for(R i = 1; i <= m; i++){
R o,l,r;
o=read(),l=read(),r=read();
IT IL=spl(l),IR=spl(r+1);
for(IT i=++IL;i!=IR;i++) rt[l]=merge(rt[l],rt[*i]);
op[l]=o;srt.erase(IL,IR);
}
R qp;
qp=read();
spl(qp),spl(qp+1);
printf("%d\n",query(rt[qp],1,n));
return 0;
}