线段树套平衡树空间计算求助
查看原帖
线段树套平衡树空间计算求助
123384
tommy0221楼主2020/5/7 15:47

RT,我感觉平衡树总结点不会超过 nlognnlogn 啊,线段树总共 lognlogn 层, 每层总共 nn 个节点,但是#2RE了好几次以后下数据发现总共有 850000850000 个节点,是我垃圾回收写挂了还是哪里算漏了?求助

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rint register int
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
char buf[1<<21],*p1=buf,*p2=buf;
inline int rd() {
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)) {if(ch=='-')f=-1;ch=getchar();}
	while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
	return x*f;
}
const int N=50010;
const int M=900000;
const int inf=2147483647;
int n,m,a[N];
int ch[M][2],val[M],rnd[M],siz[M],tot,rub[M],top,root[N<<2];
namespace fhq {
	int ne(int v) {//新建节点+垃圾回收 
		int t=top?rub[top--]:++tot;
		rnd[t]=rand();
		val[t]=v;
		ch[t][0]=ch[t][1]=0;
		siz[t]=1;
		return t;
	}
	int merge(int x,int y) {//fhq合并 
		if(!x||!y)return x|y;
		if(rnd[x]<rnd[y]) {
			ch[x][1]=merge(ch[x][1],y);
			siz[x]=1+siz[ch[x][0]]+siz[ch[x][1]];
			return x;
		} else {
			ch[y][0]=merge(x,ch[y][0]);
			siz[y]=1+siz[ch[y][0]]+siz[ch[y][1]];
			return y;
		}
	}
	void split(int u,int k,int &x,int &y) {//fhq分裂,小于等于k的在x左子树,其余在右子树 
		if(!u) {x=y=0;return;}
		if(val[u]<=k)x=u,split(ch[u][1],k,ch[u][1],y);
		else y=u,split(ch[u][0],k,x,ch[u][0]);
		siz[u]=1+siz[ch[u][0]]+siz[ch[u][1]];
	}
	void insert(int &u,int k) {//插入 
		int x,y;
		split(u,k,x,y);
		u=merge(x,merge(ne(k),y));
	}
	void del(int &u,int k) {//删除 
		int x,y,z;
		split(u,k-1,x,y);
		split(y,k,y,z);
		rub[++top]=y;
		y=merge(ch[y][0],ch[y][1]);
		u=merge(x,merge(y,z));
	}
	int rank(int u,int k) {//u为根的树,严格小于k的有几个 
		int res=0;
		while(u) {
			if(val[u]>=k)u=ch[u][0];
			else res+=siz[ch[u][0]]+1,u=ch[u][1];
		}
		return res;
	}
	int kth(int u,int k) {//u为根的树,第k大的值 
		while(u) {
			if(siz[ch[u][0]]>=k)u=ch[u][0];
			else if(siz[ch[u][0]]+1==k)return val[u];
			else k-=siz[ch[u][0]]+1,u=ch[u][1];
		}
		return -1;
	}
	int lower(int &u,int k) {//u为根的树,k的前驱 
		int res,x,y;
		split(u,k-1,x,y);
		res=kth(x,siz[x]);
		u=merge(x,y);
		return ~res?res:-inf;
	}
	int upper(int &u,int k) {//u为根的树,k的后继 
		int res,x,y;
		split(u,k,x,y);
		res=kth(y,1);
		u=merge(x,y);
		return ~res?res:inf;
	}
}
namespace seg {
	#define lc (p<<1)
	#define rc (p<<1|1) 
	void build(int l,int r,int p) {//线段树建树 
		for(rint i=l;i<=r;++i)fhq::insert(root[p],a[i]);
		if(l==r)return;
		int mid=(l+r)>>1;
		build(l,mid,lc),build(mid+1,r,rc);
	}
	void query_rank(int ql,int qr,int l,int r,int p,int k,int &res) {//查询排名 
		if(ql<=l&&r<=qr) {
			res+=fhq::rank(root[p],k);
			return;
		}
		int mid=(l+r)>>1;
		if(mid>=ql)query_rank(ql,qr,l,mid,lc,k,res);
		if(mid<qr)query_rank(ql,qr,mid+1,r,rc,k,res);
	}
	void change(int pos,int l,int r,int p,int x,bool flg) {//单点修改,flg=0插入,flg=1删除 
		if(flg)fhq::del(root[p],x);
		else fhq::insert(root[p],x);
		if(l==r)return;
		int mid=(l+r)>>1;
		if(pos<=mid)change(pos,l,mid,lc,x,flg);
		else change(pos,mid+1,r,rc,x,flg);
	}
	void query(int ql,int qr,int l,int r,int p,int k,int &res,bool flg) {//前驱后继,flg=0前驱,flg=1后继 
		if(ql<=l&&r<=qr) {
			if(flg)res=min(res,fhq::upper(root[p],k));
			else res=max(res,fhq::lower(root[p],k));
			return;
		}
		int mid=(l+r)>>1;
		if(mid>=ql)query(ql,qr,l,mid,lc,k,res,flg);
		if(mid<qr)query(ql,qr,mid+1,r,rc,k,res,flg);
	}
}
namespace sol {
	int rank(int l,int r,int k) {//操作1 
		int res=0;
		seg::query_rank(l,r,1,n,1,k,res);
		return res+1;
	}
	int kth(int ql,int qr,int k) {//操作2 
		int l=0,r=100000000,res=0;
		while(l<=r) {
			int mid=(l+r)>>1;
			if(rank(ql,qr,mid)<=k)l=mid+1,res=mid;
			else r=mid-1;
		}
		return res;
	}
	void change(int x,int y) {//操作3 
		seg::change(x,1,n,1,a[x],1);
		a[x]=y;
		seg::change(x,1,n,1,a[x],0);
	}
	int lower(int l,int r,int k) {//操作4 
		int res=-inf;
		seg::query(l,r,1,n,1,k,res,0);
		return res;
	}
	int upper(int l,int r,int k) {//操作5 
		int res=inf;
		seg::query(l,r,1,n,1,k,res,1);
		return res;
	}
}
signed main() {
	n=rd(),m=rd();
	for(rint i=1;i<=n;++i)a[i]=rd();
	seg::build(1,n,1);
	while(m--) {
		int opt=rd(),x=rd(),y=rd(),z;
		if(opt==1)z=rd(),printf("%d\n",sol::rank(x,y,z));
		else if(opt==2)z=rd(),printf("%d\n",sol::kth(x,y,z));
		else if(opt==3)sol::change(x,y);
		else if(opt==4)z=rd(),printf("%d\n",sol::lower(x,y,z));
		else z=rd(),printf("%d\n",sol::upper(x,y,z));
	}
	return 0;
} 
2020/5/7 15:47
加载中...