BZOJ3110: [Zjoi2013]K大数查询

喜闻乐见的简单树套树= =第一维按权值建树状数组,第二维按下标建动态开点线段树,修改相当于第二维区间加,查询在树状数组上二分,比一般的线段树还短= =可惜并不能跑过整体二分= =另外bzoj上的数据有负数= =其他树套树方法也是可以的爱怎么套怎么套= =

#include<cstdio>
#define J (i+j>>1)
#define I (J+1)
typedef unsigned ll;
const int N=1e5+5;
ll n,m,q,i,j,k,s,t,u,v;
struct node{
	ll s,t;
	node*i,*j;
}e[N*320];
node*a=e,*r[N];
void vary(node*&o,int s,int t,int i=1,int j=n){
	if(!o)o=a++;
	o->s+=t-s+1;
	if(s==i&&t==j)++o->t;
	else if(t<I)
		vary(o->i,s,t,i,J);
	else if(s>J)
		vary(o->j,s,t,I,j);
	else{
		vary(o->i,s,J,i,J);
		vary(o->j,I,t,I,j);
	}
}
void ask(node*o,int s,int t,int i=1,int j=n){
	if(!o)return;
	if(s==i&&t==j)u+=o->s;
	else{
		u+=o->t*(t-s+1);
		if(t<I)
			ask(o->i,s,t,i,J);
		else if(s>J)
			ask(o->j,s,t,I,j);
		else{
			ask(o->i,s,J,i,J);
			ask(o->j,I,t,I,j);
		}
	}
}
int main(){
	scanf("%d%d",&n,&q);
	m=n<<1^1;
	while(q--){
		scanf("%d%d%d%d",&j,&s,&t,&k);
		if(j==2){
			for(i=65536,v=j=0;i;i>>=1)
				if(j+i<=m){
					u=0,ask(r[j+i],s,t);
					if(v+u<k)
						j+=i,v+=u;
				}
			printf("%d\n",n-j);
		}else
			for(i=n-k+1;i<=m;i+=i&-i)
				vary(r[i],s,t);
	}
}
posted @ 2016-10-13 01:41  f321dd  阅读(274)  评论(0编辑  收藏  举报