RT,我感觉平衡树总结点不会超过 nlogn 啊,线段树总共 logn 层, 每层总共 n 个节点,但是#2RE了好几次以后下数据发现总共有 850000 个节点,是我垃圾回收写挂了还是哪里算漏了?求助
#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;
}