Task
给出1-n的全排列,m次操作分为两种:
① (0,l,r)将区间[l,r]升序排列
② (1,l,r)将区间[l,r]降序排列。
n,m<=1e5
Solution
6秒的时限,真是个暴力的好时机
用sort函数sort(A+l,A+r+1,cmp)可以对区间[l,r]升序或者降序排列,这样就有80分了。
但是本人粗鄙,写成了sort(A+l+1,A+r+1),居然还有60分
想到平时的sort都是(A,A+n)或(A+1,A+n+1),分别是左端点,右端点+1的位置。
“二分是一个方向”
二分的好处:把求知问题转化为判定问题。
类似的题目:区间第k值,中位数。
二分x,判定解是否大于等于x.按照x,记大于等于x的数为1,小于x的数为0。对于m次操作后,如果id位上的数为1,判定为可行。
问题转化为,一个01序列,m次操作后,第id位上的数是否为1。
①因为一个区间只有01,无论是升序降序,都有1个0和1的分界点。因为区间的长度是一定的,对区间求和,可以找到1的个数。
②按照分界线前部分为c,后部分为c^1.(c为0或1).
区间求和,区间更新,可以用延迟更新的线段树完成。
const int M=1e5+3;
int A[M];
int n,m,pos;
struct node1{
int cnt[2],l,r,f;
inline void clear(){
memset(cnt,0,sizeof(cnt));
}
}res;
struct node2{
int a,l,r;
}Q[M];
struct Segment_Tree{
node1 t[M<<2];
inline void up(int p){
rep(i,0,1)
t[p].cnt[i]=t[lsn(p)].cnt[i]+t[rsn(p)].cnt[i];
}
inline void down(int p){
if(t[p].f==-1)return;
int c=t[p].f,l=lsn(p),r=rsn(p);
t[l].f=t[r].f=c;
t[l].cnt[c]=t[l].r-t[l].l+1;
t[r].cnt[c]=t[r].r-t[r].l+1;
t[l].cnt[c^1]=t[r].cnt[c^1]=0;
t[p].f=-1;
}
inline void build(int l,int r,int x,int p){
t[p].l=l,t[p].r=r;t[p].f=-1;
if(l==r){
bool a=(A[l]>=x);
t[p].cnt[a]=1;t[p].cnt[a^1]=0;
return;
}
int mid=l+r>>1;
build(l,mid,x,lsn(p));
build(mid+1,r,x,rsn(p));
up(p);
}
inline void query(int L,int R,int l,int r,int p){
if(l==L&&r==R){
rep(i,0,1)res.cnt[i]+=t[p].cnt[i];
return;
}
down(p);
int mid=L+R>>1;
if(r<=mid)query(L,mid,l,r,lsn(p));
else if(l>mid)query(mid+1,R,l,r,rsn(p));
else{
query(L,mid,l,mid,lsn(p));
query(mid+1,R,mid+1,r,rsn(p));
}
}
inline void update(int L,int R,int l,int r,int c,int p){//区间刷成c颜色
if(l==L&&r==R){
t[p].cnt[c]=r-l+1;
t[p].cnt[c^1]=0;
t[p].f=c;
return;
}
down(p);
int mid=L+R>>1;
if(r<=mid)update(L,mid,l,r,c,lsn(p));
else if(l>mid)update(mid+1,R,l,r,c,rsn(p));
else{
update(L,mid,l,mid,c,lsn(p));
update(mid+1,R,mid+1,r,c,rsn(p));
}
up(p);
}
}T;
struct P100{
inline void input(){
rd(n);rd(m);
rep(i,1,n)rd(A[i]);
rep(i,1,m){
rd(Q[i].a);rd(Q[i].l);rd(Q[i].r);
}
rd(pos);
}
inline bool check(int x){//解是否>=x
int a,l,r;
T.build(1,n,x,1);
rep(i,1,m){
res.clear();
a=Q[i].a,l=Q[i].l,r=Q[i].r;
T.query(1,n,l,r,1);
if(min(res.cnt[0],res.cnt[1])==0)continue;//这个区间都是0或1
T.update(1,n,l,l+res.cnt[a]-1,a,1);//区间刷成颜色a
T.update(1,n,l+res.cnt[a],r,a^1,1);//区间刷成颜色a^1
}
res.clear();
T.query(1,n,pos,pos,1);
return res.cnt[1]==1;
}
inline void solve(){
input();
int l=1,r=n,mid,ans;
while(l<=r){
mid=l+r>>1;
if(check(mid)){l=mid+1;ans=mid;}
else r=mid-1;
}
sc(ans);
}
}P100;
int main(){
P100.solve();
return 0;
}