1. 程式人生 > 實用技巧 >#線段樹,二分#洛谷 2824 [HEOI2016/TJOI2016]排序

#線段樹,二分#洛谷 2824 [HEOI2016/TJOI2016]排序

題目


分析

這排序就很難實現,考慮定一個基準,小於該基準的視為0,否則視為1,
那排序可以看作將0和1分開,這就很好用線段樹實現了
如果該位置是0,說明這個基準太高,顯然可以用二分答案(基準),那麼時間複雜度就是\(O((n+m)log^2n)\)


程式碼

#include <cstdio>
#include <cctype> 
#define rr register
using namespace std;
const int N=100011;
int lazy[N<<2],w[N<<2],a[N],n,L[N],R[N],m;
inline signed iut(){
	rr int ans=0; rr char c=getchar();
	while (!isdigit(c)) c=getchar();
	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
	return ans;
}
inline void build(int k,int l,int r,int now){
	if (l==r) {lazy[k]=-1,w[k]=a[l]>=now; return;}
	rr int mid=(l+r)>>1;
	build(k<<1,l,mid,now),build(k<<1|1,mid+1,r,now);
	w[k]=w[k<<1]+w[k<<1|1],lazy[k]=-1;
}
inline void pdown(int k,int l,int r){
	rr int mid=(l+r)>>1;
	if (lazy[k]) w[k<<1]=mid-l+1,w[k<<1|1]=r-mid;
	    else w[k<<1]=w[k<<1|1]=0;
	lazy[k<<1]=lazy[k<<1|1]=lazy[k],lazy[k]=-1;
}
inline void update(int k,int l,int r,int x,int y,int z){
	if (l==x&&r==y) {w[k]=z*(r-l+1),lazy[k]=z; return;}
	if (~lazy[k]) pdown(k,l,r);
	rr int mid=(l+r)>>1;
	if (y<=mid) update(k<<1,l,mid,x,y,z);
	    else if (x>mid) update(k<<1|1,mid+1,r,x,y,z);
	        else update(k<<1,l,mid,x,mid,z),update(k<<1|1,mid+1,r,mid+1,y,z);
    w[k]=w[k<<1]+w[k<<1|1];
}
inline signed query(int k,int l,int r,int x,int y){
	if (l==x&&r==y) return w[k];
	if (~lazy[k]) pdown(k,l,r);
	rr int mid=(l+r)>>1;
	if (y<=mid) return query(k<<1,l,mid,x,y);
	    else if (x>mid) return query(k<<1|1,mid+1,r,x,y);
	        else return query(k<<1,l,mid,x,mid)+query(k<<1|1,mid+1,r,mid+1,y);
}
inline bool check(int now,int pos){
	build(1,1,n,now);
	for (rr int i=1,f;i<=m;++i){
		if (L[i]<0) f=-1,L[i]=-L[i]; else f=1;
		rr int cnt=query(1,1,n,L[i],R[i]),h=R[i]-L[i]+1;
		if (~f){
		    if (cnt<h) update(1,1,n,L[i],R[i]-cnt,0);
			if (cnt) update(1,1,n,R[i]-cnt+1,R[i],1);
	    }
		else{
			if (cnt<h) update(1,1,n,L[i]+cnt,R[i],0);
		    if (cnt) update(1,1,n,L[i],L[i]+cnt-1,1);
		}
		L[i]*=f;
	}
	return query(1,1,n,pos,pos);
}
signed main(){
	n=iut(); m=iut();
	for (rr int i=1;i<=n;++i) a[i]=iut();
	for (rr int i=1;i<=m;++i){
		rr int z=iut()?-1:1;
		L[i]=iut()*z,R[i]=iut();
	}
	rr int l=1,r=n,pos=iut();
	while (l<r){
		rr int mid=(l+r+1)>>1;
		if (check(mid,pos)) l=mid;
		    else r=mid-1;
	}
	return !printf("%d",l);
}