一道神奇的线段树+二分法的题。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define rchild o<<1|1
#define lchild o<<1
#define mid (l+r>>1)
const int N=100005;
int sum[N<<2],lazy[N<<2];
int a[N],t[N];
int Q;
int x[N],y[N];
int op[N];
inline void pushup(int o)
{
sum[o]=sum[lchild]+sum[rchild];
}
inline void pushdown(int o,int l,int r)
{
if(l==r) return;
int t=lazy[o];
lazy[o]=-1;
lazy[lchild]=lazy[rchild]=t;
sum[lchild]=(mid-l+1)*t,sum[rchild]=(r-mid)*t;
}
inline void change(int o,int l,int r,int x,int y,int z)
{
if(lazy[o]!=-1) pushdown(o,l,r);
if(l==x && r==y)
{
sum[o]=(r-l+1)*z;
lazy[o]=z;
return;
}
if(y<=mid) change(lchild,l,mid,x,y,z);
if(x>mid) change(rchild,mid+1,r,x,y,z);
if(x<=mid && y>mid)
{
change(lchild,l,mid,x,mid,z);
change(rchild,mid+1,r,mid+1,y,z);
}
pushup(o);
}
inline int query(int o,int l,int r,int x,int y)
{
if(lazy[o]!=-1) pushdown(o,l,r);
if(l==x && r==y)
{
return sum[o];
}
if(y<=mid) return query(lchild,l,mid,x,y);
if(x>mid) return query(rchild,mid+1,r,x,y);
if(x<=mid && y>mid)
return query(lchild,l,mid,x,mid)+query(rchild,mid+1,r,mid+1,y);
}
int n,m;
bool check(int midd)
{
memset(sum,0,sizeof sum);
memset(lazy,-1,sizeof lazy);
for(int i=1;i<=n;i++)
{
if(a[i]>midd) t[i]=1;
else t[i]=0;
if(t[i]==1) change(1,1,n,i,i,1);
}
for(int i=1;i<=m;i++)
{
int num=query(1,1,n,x[i],y[i]);
if(num==0) continue;
if(num==(y[i]-x[i]+1)) continue;
else
{
change(1,1,n,x[i],y[i],0);
if(op[i]==1) change(1,1,n,x[i],x[i]+num-1,1);
else change(1,1,n,y[i]-num+1,y[i],1);
}
}
int num=query(1,1,n,Q,Q);
return !num;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&op[i],&x[i],&y[i]);
}
scanf("%d",&Q);
int l,r;
l=1,r=n;
while(l!=r)
{
int midd=(l+r)>>1;
if(check(midd)) r=midd;
else l=midd+1;
}
printf("%d\n",l);
return 0;
}