luoguP2824 [HEOI2016/TJOI2016]排序 二分+线段树
题意:给定一个排列,每次有两种操作:1 区间降序排列 2 区间升序排列,求 m 才操作后 q 位置上的数字
这道题非常神仙啊.
假如说序列中只有 0,1 的话我们只需要用线段树维护 0,1的个数然后进行区间覆盖即可.
由于所有数互不相同,考虑二分 $q$ 点上的数 $mid$,然后将大于等于 $mid$ 的设置成 $1$,小于的设置成 $0$.
然后我们对新构建的序列从头到尾操作一下,发现如果 $q$ 位置是 $1$ 的话答案要大于等于 $mid$,反之亦然.
那么这个 $q$ 点的答案就满足单调性了,可以二分.
总时间复杂度为 $O(n \log^2 n)$
code:
#include <bits/stdc++.h>
#define N 100009
#define lson now<<1
#define rson now<<1|1
#define ll long long
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
int n,as,m;
int a[N],b[N];
int c[2][N<<2],t[2][N<<2],len[N<<2];
struct data {
int l,r,op;
}p[N];
void pushup(int now) {
c[0][now]=c[0][lson]+c[0][rson];
c[1][now]=c[1][lson]+c[1][rson];
}
void mark(int now,int v) {
t[v][now]=1,t[v^1][now]=0;
c[v][now]=len[now],c[v^1][now]=0;
}
void pushdown(int now) {
if(t[0][now]) mark(lson,0),mark(rson,0),t[0][now]=0;
if(t[1][now]) mark(lson,1),mark(rson,1),t[1][now]=0;
}
void build(int l,int r,int now) {
c[0][now]=c[1][now]=0;
t[0][now]=t[1][now]=0;
len[now]=r-l+1;
if(l==r) {
c[b[l]][now]=1;
return;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
pushup(now);
}
int query(int l,int r,int now,int L,int R,int v) {
if(l>=L&&r<=R) return c[v][now];
int mid=(l+r)>>1,re=0;
pushdown(now);
if(L<=mid) re+=query(l,mid,lson,L,R,v);
if(R>mid) re+=query(mid+1,r,rson,L,R,v);
return re;
}
void upd(int l,int r,int now,int L,int R,int v) {
if(l>=L&&r<=R) { mark(now,v); return; }
int mid=(l+r)>>1;
pushdown(now);
if(L<=mid) upd(l,mid,lson,L,R,v);
if(R>mid) upd(mid+1,r,rson,L,R,v);
pushup(now);
}
int check(int tmp) {
for(int i=1;i<=n;++i) b[i]=(a[i]>=tmp);
build(1,n,1);
int l,r,op,x,y,z;
for(int i=1;i<=m;++i) {
l=p[i].l,r=p[i].r,op=p[i].op;
if(op==0) {
x=query(1,n,1,l,r,0);
y=query(1,n,1,l,r,1);
if(x) upd(1,n,1,l,l+x-1,0);
if(y) upd(1,n,1,r-y+1,r,1);
}
else {
x=query(1,n,1,l,r,0);
y=query(1,n,1,l,r,1);
if(y) upd(1,n,1,l,l+y-1,1);
if(x) upd(1,n,1,r-x+1,r,0);
}
}
return query(1,n,1,as,as,1);
}
int main() {
// setIO("input");
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",&p[i].op,&p[i].l,&p[i].r);
}
scanf("%d",&as);
int l=1,r=n,ans=0,mid;
while(l<=r) {
mid=(l+r)>>1;
if(check(mid)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
return 0;
}

浙公网安备 33010602011771号