[ZJOI2013]K大数查询

VII.[ZJOI2013]K大数查询

这题常卡的我快哭了QaQ

首先,我们仍然考虑树套树。

  1. 下标树套权值树(即我们前几题的一贯做法)

我们发现,要在区间树上打上区间添加数的tag,并且用tag树的并集进行二分。

因此最终的结果就是,大区间被分割成\(\log n\)个小区间,但是每个小区间的\(\log n\)个父亲区间的tag树都是必须选的。因此总共有\(\log^2n\)tag树在一起二分,因此总复杂度就是\(\log^3n\)的。并且写起来还贼恶心。介于这题贼卡长,我不认为这种方法有通过的可能性。

  1. 权值树套下标树

现在,我们就是在权值树的某个叶节点上的下标树内,打上一个区间加的tag。当然咯,这叶节点的所有父亲的下标树,也是要打tag的。

最终的结果就是,修改就是在\(\log n\)个下标树内打区间加tag,复杂度\(\log^2n\)

然后询问。就直接在权值树上二分,同时在下标树上查询区间和,复杂度\(\log^2n\)

被卡长的代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,Inc,root[200100],dis[200100],tp;
struct Inner{
	int lson,rson,tag;
	ll sum;
}inn[20010000];
inline void pushdown(const register int &x,const register int &l,const register int &r){
	register int mid=(l+r)>>1,&val=inn[x].tag;
	if(!inn[x].lson)inn[x].lson=++Inc;
	if(!inn[x].rson)inn[x].rson=++Inc;
	inn[inn[x].lson].sum+=1ll*val*(mid-l+1),inn[inn[x].lson].tag+=val;
	inn[inn[x].rson].sum+=1ll*val*(r-mid),inn[inn[x].rson].tag+=val;
	val=0;
}
inline void Inner_Add(register int &x,const register int &l,const register int &r,const register int &L,const register int &R){
	if(!x)x=++Inc;
	if(L<=l&&r<=R){inn[x].sum+=r-l+1,inn[x].tag++;return;}
	if(inn[x].tag)pushdown(x,l,r);
	register int mid=(l+r)>>1;
	if(mid>=L)Inner_Add(inn[x].lson,l,mid,L,R);
	if(mid<R)Inner_Add(inn[x].rson,mid+1,r,L,R);
	inn[x].sum=inn[inn[x].lson].sum+inn[inn[x].rson].sum;
}
inline ll Inner_Ask(const register int &x,const register int &l,const register int &r,const register int &L,const register int &R){
	if(L<=l&&r<=R)return inn[x].sum;
	if(inn[x].tag)pushdown(x,l,r);
	register int mid=(l+r)>>1;
	ll res=0;
	if(mid>=L&&inn[x].lson)res+=Inner_Ask(inn[x].lson,l,mid,L,R);
	if(mid<R&&inn[x].rson)res+=Inner_Ask(inn[x].rson,mid+1,r,L,R);
	return res;
}
inline void Outer_Add(const register int &x,const register int &l,const register int &r,const register int &P,const register int &L,const register int &R){
	Inner_Add(root[x],1,n,L,R);
	if(l==r)return;
	register int mid=(l+r)>>1;
	if(mid>=P)Outer_Add(x<<1,l,mid,P,L,R);
	else Outer_Add(x<<1|1,mid+1,r,P,L,R);
}
inline int Outer_Ask(const register int &x,const register int &l,const register int &r,const register int &L,const register int &R,const register ll &k){
	if(l==r)return l;
	register ll rsum=Inner_Ask(root[x<<1|1],1,n,L,R);
	register int mid=(l+r)>>1;
	if(rsum>=k)return Outer_Ask(x<<1|1,mid+1,r,L,R,k);
	else return Outer_Ask(x<<1,l,mid,L,R,k-rsum);
}
struct Query{
	int tp,l,r;
	ll k;
}q[50100];
inline void read(register int &x){
	register char c=getchar();
	register int fl=1;
	while(c>'9'||c<'0')fl=(c=='-'?-fl:fl),c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	x*=fl;
}
inline void read(register ll &x){
	register char c=getchar();
	register int fl=1;
	while(c>'9'||c<'0')fl=(c=='-'?-fl:fl),c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	x*=fl;
}
inline void print(register int x){
	if(x<0)putchar('-'),print(-x);
	else if(x<=9)putchar('0'+x);
	else print(x/10),putchar('0'+x%10);
}
int main(){
	read(n),read(m);
	for(register int i=1;i<=m;i++){
		read(q[i].tp),read(q[i].l),read(q[i].r),read(q[i].k);
		if(q[i].tp==1)dis[++tp]=q[i].k;
	}
	sort(dis+1,dis+tp+1),tp=unique(dis+1,dis+tp+1)-dis-1;
	for(register int i=1;i<=m;i++){
		if(q[i].tp==1)Outer_Add(1,1,tp,lower_bound(dis+1,dis+tp+1,q[i].k)-dis,q[i].l,q[i].r);
		else print(dis[Outer_Ask(1,1,tp,q[i].l,q[i].r,q[i].k)]),putchar('\n');
	}
	return 0;
}

能用的优化就只有在下标树上的标记永久化了。

因此现学了这个东西,敲出来常数果然快了很多,勉强卡过了:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int n,m,Inc,root[200100],dis[200100],tp;
struct Inner{
	int lson,rson,tag;
	ll sum;
}inn[20010000];
inline void Inner_Add(register int &x,const register int &l,const register int &r,const register int &L,const register int &R){
	if(!x)x=++Inc;
	inn[x].sum+=max(min(R,r)-max(L,l)+1,0);
	if(L<=l&&r<=R){inn[x].tag++;return;}
	register int mid=(l+r)>>1;
	if(mid>=L)Inner_Add(inn[x].lson,l,mid,L,R);
	if(mid<R)Inner_Add(inn[x].rson,mid+1,r,L,R);
}
inline ll Inner_Ask(const register int &x,const register int &l,const register int &r,const register int &L,const register int &R,const register int add=0){
	if(!x)return 1ll*add*max(min(R,r)-max(L,l)+1,0);
	if(L<=l&&r<=R)return 1ll*add*(r-l+1)+inn[x].sum;
	register int mid=(l+r)>>1;
	register ll res=0;
	if(mid>=L)res+=Inner_Ask(inn[x].lson,l,mid,L,R,add+inn[x].tag);
	if(mid<R)res+=Inner_Ask(inn[x].rson,mid+1,r,L,R,add+inn[x].tag);
	return res;
}
inline void Outer_Add(const register int &x,const register int &l,const register int &r,const register int &P,const register int &L,const register int &R){
	Inner_Add(root[x],1,n,L,R);
	if(l==r)return;
	register int mid=(l+r)>>1;
	if(mid>=P)Outer_Add(x<<1,l,mid,P,L,R);
	else Outer_Add(x<<1|1,mid+1,r,P,L,R);
}
inline int Outer_Ask(const register int &x,const register int &l,const register int &r,const register int &L,const register int &R,const register ll &k){
	if(l==r)return l;
	register ll rsum=Inner_Ask(root[x<<1|1],1,n,L,R);
	register int mid=(l+r)>>1;
	if(rsum>=k)return Outer_Ask(x<<1|1,mid+1,r,L,R,k);
	else return Outer_Ask(x<<1,l,mid,L,R,k-rsum);
}
struct Query{
	int tp,l,r;
	ll k;
}q[50100];
inline void read(register int &x){
	register char c=getchar();
	register int fl=1;
	while(c>'9'||c<'0')fl=(c=='-'?-fl:fl),c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	x*=fl;
}
inline void read(register ll &x){
	register char c=getchar();
	register int fl=1;
	while(c>'9'||c<'0')fl=(c=='-'?-fl:fl),c=getchar();
	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
	x*=fl;
}
inline void print(register int x){
	if(x<0)putchar('-'),print(-x);
	else if(x<=9)putchar('0'+x);
	else print(x/10),putchar('0'+x%10);
}
int main(){
	read(n),read(m);
	for(register int i=1;i<=m;i++){
		read(q[i].tp),read(q[i].l),read(q[i].r),read(q[i].k);
		if(q[i].tp==1)dis[++tp]=q[i].k;
	}
	sort(dis+1,dis+tp+1),tp=unique(dis+1,dis+tp+1)-dis-1;
	for(register int i=1;i<=m;i++){
		if(q[i].tp==1)Outer_Add(1,1,tp,lower_bound(dis+1,dis+tp+1,q[i].k)-dis,q[i].l,q[i].r);
		else print(dis[Outer_Ask(1,1,tp,q[i].l,q[i].r,q[i].k)]),putchar('\n');
	}
	return 0;
}

原文地址:https://www.cnblogs.com/Troverld/p/14611124.html