洛谷 P3332 [ZJOI2013]K大数查询

题目:K大数查询
思路:

整体二分。
维护两个区间[L,R]和[l,r],分别代表二分的答案区间,和可以满足答案的询问区间。
在[L,R]上二分M。
对于1操作,如果v小于M,在[q.l,q.r]上用线段树实现区间加一,值赋1,否则赋0。
对于2操作,询问[q.l,q.r]上的数的个数s,若v小于等于s,值赋1,否则赋0。
注意long long的使用,以及线段树打标记清空。

代码:
#include
using namespace std;

#define maxn 50000
#define ll long long
#define readll(x) scanf("%lld",&x)
#define read(x) scanf("%d",&x)

struct SEG{
	int P,Q;
	ll c[maxn*10],lzy[maxn*10];
	bool clr[maxn*10];
	SEG(){}
	
	#define lson o*2
	#define rson o*2+1
	
	void init() {clr[1]=1;c[1]=lzy[1]=0;}
	
	void push_down(int o,int L,int mid,int R) {
		if(clr[o]) {
			clr[lson]=clr[rson]=1;
			c[lson]=c[rson]=lzy[lson]=lzy[rson]=0;
			clr[o]=0;
		}
		lzy[lson]+=lzy[o],lzy[rson]+=lzy[o];
		c[lson]+=lzy[o]*(mid-L+1),c[rson]+=lzy[o]*(R-mid);
		lzy[o]=0;
	}
	
	void push_up(int o) {c[o]=c[lson]+c[rson];}
	
	void Add(int o,int L,int R) {
		int mid=(L+R)/2;
		push_down(o,L,mid,R);
		if(L>=P&&R<=Q) {
			c[o]+=(R-L+1),lzy[o]++;
			return ;
		}
		if(L>Q||R<P) return ; 
		
		Add(lson,L,mid),Add(rson,mid+1,R);
		push_up(o);
	}
	
	ll Query(int o,int L,int R) {
		int mid=(L+R)/2;
		push_down(o,L,mid,R);
		if(L>=P&&R<=Q) return c[o];
		if(L>Q||R<P) return 0;
		
		return Query(lson,L,mid)+Query(rson,mid+1,R);
	}
};

SEG seg,emp;

struct Q{
	int opr,l,r;ll v;
	int id,k;
	Q(){}
	bool operator <(const Q& oth) const{
		if(k==oth.k) return id<oth.id;
		else return k<oth.k;
	}
};

int n,m;
Q q[maxn+5];

int ans[maxn+5];

void readin() {
	read(n),read(m);
	for(int i=1;i<=m;i++) {
		read(q[i].opr),read(q[i].l),read(q[i].r),readll(q[i].v),q[i].id=i;
	}
}

void binsearch(int L,int R,int l,int r) {
	if(l>r) return ;
	if(L==R) {
		for(int i=l;i<=r;i++) if(q[i].opr==2) ans[q[i].id]=L;
		return ;
	}
	
	seg.init();
	int M=(L+R)/2,t=l-1;
	for(int i=l;i<=r;i++) {
		seg.P=q[i].l,seg.Q=q[i].r;
		if(q[i].opr==1) {
			if(q[i].v>M) seg.Add(1,1,n),q[i].k=1;
			else t++,q[i].k=0;
		} else {
			ll s=seg.Query(1,1,n);
			if(q[i].v<=s) q[i].k=1;
			else t++,q[i].k=0,q[i].v-=s;
		}
	}
	sort(q+l,q+r+1);
	binsearch(L,M,l,t),binsearch(M+1,R,t+1,r);
}

int main() {
	readin();
	memset(ans,-1,sizeof(ans));
	binsearch(0,n,1,m);
	for(int i=1;i<=m;i++) if(~ans[i]) printf("%d\n",ans[i]);
	return 0;
}

你可能感兴趣的:(整体二分)