P3332 [ZJOI2013]K大数查询

题目

P3332 [ZJOI2013]K大数查询

一眼似乎不可做。。。结果眼瞎看错题了,切了切了

做法

化简题意:\(n\)个集合,\(m\)次操作(集合区间添数,集合区间查询\(K\)大值)

外层值域线段树+内存区间线段树,自己去随便\(yy\)一下也能切掉吧

还是讲一下具体做法:添的数\(long long\)以内,值域线段树空间会被卡,去重

关于添数,找到\(c\)在值域内的位置,结果的线段树内层\((a,b)+1\),其实这个树套树维护的就是在\((l,r)\)这个值域集合区间出现的数

有点卡常:值域非递归做一下,\(int\)\(long long\)要准确区分位置,吸波氧可过

My complete code

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
typedef int LL;
const LL maxn=20000000;
inline LL Read(){
	LL x(0),f(1);char c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+c-'0',c=getchar();
	return x*f;
}
struct Qy{
	LL op,a,b;
	long long c;
}q[maxn];
LL n,m,nod,cnt;
LL son[maxn][2],root[maxn];
long long tmp[maxn],sum[maxn],lazy[maxn];
inline void Update(LL now){
	sum[now]=sum[son[now][0]]+sum[son[now][1]];
}
inline void Pushdown(LL now,LL l,LL r){
	LL val(lazy[now]);
	if(val){
		LL mid(l+r>>1);
		lazy[now]=0;
		if(!son[now][0]) son[now][0]=++nod;
		if(!son[now][1]) son[now][1]=++nod;
		LL lc(son[now][0]),rc(son[now][1]);
		lazy[lc]+=val,lazy[rc]+=val,
		sum[lc]+=(mid-l+1)*val,sum[rc]+=(r-mid)*val;
	}
}
void Add(LL &now,LL l,LL r,LL lt,LL rt){
	if(!now) now=++nod;
	if(lt<=l&&rt>=r){
		sum[now]+=(r-l+1),
		++lazy[now];
		return;
	}
	Pushdown(now,l,r);
	LL mid(l+r>>1);
	if(lt<=mid) Add(son[now][0],l,mid,lt,rt);
	if(rt>mid)  Add(son[now][1],mid+1,r,lt,rt);
	Update(now);
}
long long Query(LL now,LL l,LL r,LL lt,LL rt){
	if(!now) return 0;
	if(lt<=l&&rt>=r) return sum[now];
	Pushdown(now,l,r);
	LL mid(l+r>>1);long long ret(0);
	if(lt<=mid) ret+=Query(son[now][0],l,mid,lt,rt);
	if(rt>mid) ret+=Query(son[now][1],mid+1,r,lt,rt);
	return ret;
}
void SAdd(LL x,LL l,LL r,LL c,LL a,LL b){
	while(l!=r){
		Add(root[x],1,n,a,b);
		LL mid(l+r>>1);
		if(c<=mid)
			x=(x<<1),r=mid;
		else
			x=(x<<1|1),l=mid+1;
	}
	Add(root[x],1,n,a,b);
}
LL SQuery(LL x,LL l,LL r,LL a,LL b,long long K){
	while(l!=r){
		LL mid(l+r>>1);long long ret=Query(root[x<<1|1],1,n,a,b);
		if(K<=ret)
		    x=(x<<1|1),l=mid+1;
		else
		    x=(x<<1),r=mid,K-=ret;
	}return tmp[l];
}
int main(){
	n=Read(),m=Read();
	for(LL i=1;i<=m;++i){
		q[i]=(Qy){Read(),Read(),Read(),0};
		scanf("%lld",&q[i].c);
		if(q[i].op==1) tmp[++cnt]=q[i].c;
	}
	sort(tmp+1,tmp+1+cnt),cnt=unique(tmp+1,tmp+1+cnt)-tmp-1;
	for(LL i=1;i<=m;++i){
		if(q[i].op==1){
			LL val(lower_bound(tmp+1,tmp+1+cnt,q[i].c)-tmp);
			SAdd(1,1,cnt,val,q[i].a,q[i].b);
		}else
		    printf("%lld\n",SQuery(1,1,cnt,q[i].a,q[i].b,q[i].c));
	}return 0;
}
posted @ 2019-01-27 10:13  y2823774827y  阅读(185)  评论(0编辑  收藏  举报