处理方式——[HE/TJOI2016]排序

https://www.luogu.com.cn/problem/P2824

从这个题的二分答案确实不太好想。主要地,这题有两个切入点:①区间排序②离线单点询问。

从①的话,可能可以想到对 01 序列的排序可以用线段树维护;
从②的话,可能可以想到二分答案是否大于等于 \(x\),从而人为造成单调性。

所以本题的做法是二分 \(a_q\) 是否 \(\ge x\),并将序列中 \(\ge x,<x\) 的分别设为 \(1,0\),对新序列(是个 01 序列)的排序只需要支持区间和、区间赋值操作。

#include <bits/stdc++.h>
using namespace std;
const int N=1e5+5;
inline int read(){
	register char ch=getchar();register int x=0;
	while(ch<'0'||ch>'9')ch=getchar();
	while(ch>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
	return x;
}
int n,m,p,a[N],b[N],t[N<<2],tag[N<<2];
struct J{int op,l,r;}q[N];
void pushup(int k){
	t[k]=t[k<<1]+t[k<<1|1];
}
void pushdown(int l,int r,int k){
	if(tag[k]<0)return;
	int mid=l+r>>1;
	tag[k<<1]=tag[k],tag[k<<1|1]=tag[k];
	t[k<<1]=(mid-l+1)*tag[k],t[k<<1|1]=(r-mid)*tag[k];
	tag[k]=-1;
}
void build(int l,int r,int k){
	tag[k]=-1;
	if(l==r){t[k]=b[l];return;}
	int mid=l+r>>1;
	build(l,mid,k<<1),build(mid+1,r,k<<1|1);
	pushup(k);
}
void chg(int L,int R,int v,int l,int r,int k){
	if(L<=l&&r<=R){t[k]=(r-l+1)*v;tag[k]=v;return;}
	pushdown(l,r,k);
	int mid=l+r>>1;
	if(L<=mid)chg(L,R,v,l,mid,k<<1);
	if(R>mid)chg(L,R,v,mid+1,r,k<<1|1);
	pushup(k);
}
int ask(int L,int R,int l,int r,int k){
	if(L<=l&&r<=R)return t[k];
	pushdown(l,r,k);
	int mid=l+r>>1,ans=0;
	if(L<=mid)ans+=ask(L,R,l,mid,k<<1);
	if(R>mid)ans+=ask(L,R,mid+1,r,k<<1|1);
	return ans;
}
bool check(int x){
	for(int i=1;i<=n;i++)b[i]=a[i]>=x;
	build(1,n,1);
	for(int i=1;i<=m;i++){
		int t=ask(q[i].l,q[i].r,1,n,1);
		if(!q[i].op){
			if(t)chg(q[i].r-t+1,q[i].r,1,1,n,1);
			if(q[i].r-t>=q[i].l)chg(q[i].l,q[i].r-t,0,1,n,1);
		}
		else {
			if(t)chg(q[i].l,q[i].l+t-1,1,1,n,1);
			if(q[i].l+t<=q[i].r)chg(q[i].l+t,q[i].r,0,1,n,1);
		}
	}
	return ask(p,p,1,n,1);
}
int main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)a[i]=read();
	for(int i=1;i<=m;i++)q[i].op=read(),q[i].l=read(),q[i].r=read();
	p=read();
	int L=0,R=n+1,mid;
	while(L<R-1){
		mid=L+R>>1;
		if(check(mid))L=mid;
		else R=mid;
	}
	cout<<L;
}
posted @ 2022-03-02 17:06  pengyule  阅读(16)  评论(0编辑  收藏  举报