题目概述
给出一个 n 的排列,对其进行
解题报告
又是二分神题Orz,先二分答案 mid ,就可以把序列按照是否大于 mid 变为 01 序列,这样局部排序就变成了 01 个数查询和区间覆盖。如果最后 pos 上是 1 ,说明答案不小于
示例程序
#include<cstdio>
#include<algorithm>
#define fr first
#define sc second
using namespace std;
const int maxn=100000;
int n,m,pos,now,a[maxn+5],sum[(maxn<<2)+5],tag[(maxn<<2)+5];
pair<int, pair<int,int> > q[maxn+5];
#define LS (p<<1)
#define RS (p<<1|1)
#define Pushup(p) sum[p]=sum[LS]+sum[RS]
void Build(int L,int R,int p=1)
{
int mid=L+(R-L>>1);if (L==R) {sum[p]=a[mid]>=now;return;}
tag[p]=-1;Build(L,mid,LS);Build(mid+1,R,RS);Pushup(p);
}
inline void Pushdown(int l,int r,int p)
{
if (tag[p]==-1) return;int now=tag[p],mid=l+(r-l>>1);tag[p]=-1;
sum[LS]=now*(mid-l+1);tag[LS]=now;sum[RS]=now*(r-mid);tag[RS]=now;
}
void Cover(int L,int R,int k,int l=1,int r=n,int p=1)
{
if (R<l||r<L) return;if (L<=l&&r<=R) {sum[p]=k*(r-l+1);tag[p]=k;return;}
Pushdown(l,r,p);int mid=l+(r-l>>1);
Cover(L,R,k,l,mid,LS);Cover(L,R,k,mid+1,r,RS);Pushup(p);
}
int Ask(int L,int R,int l=1,int r=n,int p=1)
{
if (R<l||r<L) return 0;if (L<=l&&r<=R) return sum[p];
Pushdown(l,r,p);int mid=l+(r-l>>1);
return Ask(L,R,l,mid,LS)+Ask(L,R,mid+1,r,RS);
}
inline bool check()
{
for (int i=1;i<=m;i++)
{
int td=q[i].fr,L=q[i].sc.fr,R=q[i].sc.sc,num=Ask(L,R);
if (!td) Cover(L,R-num,0),Cover(R-num+1,R,1); else
Cover(L,L+num-1,1),Cover(L+num,R,0);
}
return Ask(pos,pos);
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
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",&q[i].fr,&q[i].sc.fr,&q[i].sc.sc);
int L=1,R=n;scanf("%d",&pos);
for (now=L+(R-L>>1);L<=R;now=L+(R-L>>1))
if (Build(1,n),check()) L=now+1; else R=now-1;
return printf("%d\n",R),0;
}