警示后人&求助
查看原帖
警示后人&求助
309320
懵逼小蒟蒻楼主2024/6/16 12:44

我写的是线段树套动态开点权值线段树。

#include<bits/stdc++.h>
using namespace std;
const int N = 50005,inf = 2147483647;
struct T{
	int l,r,mid,rid;	
}t[8*N];
struct iT{
	int ls,rs;
	unsigned short sum;
}it[605*N];
int tot,a[N],lsa[2*N];
//int iq[N],iqt;
int cr(){
	int p = ++tot;
//	if(iqt)p = iq[iqt--];
//	else p = ++tot;
	it[p].ls = it[p].rs = it[p].sum = 0;
	return p;
}
void udi(int p){
	it[p].sum = it[it[p].ls].sum+it[it[p].rs].sum;
}
void cgi(int &p,int to,int l,int r,int k){
	if(!p)p = cr();
	if(l==r){
		it[p].sum+=k;
		//if(!it[p].sum)iq[++iqt] = p,p = 0;
		return;
	}
	int mid = (l+r)>>1;
	if(to<=mid)cgi(it[p].ls,to,l,mid,k);
	else cgi(it[p].rs,to,mid+1,r,k);
	udi(p);
	//if(!it[p].sum)iq[++iqt] = p,p = 0;
}
void build(int p,int l,int r){
	t[p].l = l;t[p].r = r;t[p].mid = (l+r)>>1;
	t[p].rid = 0;
	for(int i = l;i<=r;i++)cgi(t[p].rid,a[i],1,2*N,1);
	if(l==r)return;
	build(p<<1,l,t[p].mid);
	build((p<<1)|1,t[p].mid+1,r);
}
void cgo(int p,int to,int k){
	cgi(t[p].rid,a[to],1,2*N,-1);
	cgi(t[p].rid,k,1,2*N,1);
	if(t[p].l==t[p].r){
		a[t[p].l] = k;
		return;
	}
	if(to<=t[p].mid)cgo(p<<1,to,k);
	else cgo((p<<1)|1,to,k);
}
int n,m,ct;
struct Q{
	int op,l,r,k;
}q[N];
int rs(int a){
	return lower_bound(lsa+1,lsa+ct+1,a)-lsa;
}
int que[N],qt; 
void split(int p,int l,int r){
	if(l<=t[p].l&&t[p].r<=r){
		que[++qt] = p;
		return;
	}
	if(t[p].mid>=l)split(p<<1,l,r);
	if(t[p].mid<r)split((p<<1)|1,l,r);
}
//here
int qri(int p,int l,int r,int L,int R){
	//here
	//MLE on 10:if(L<=l&&r<=R)return it[p].sum;
	if(L<=l&&r<=R||!p)return it[p].sum;
	int mid = (l+r)>>1,ans = 0;
	if(mid>=L)ans+=qri(it[p].ls,l,mid,L,R);
	if(mid<R)ans+=qri(it[p].rs,mid+1,r,L,R);
	return ans;	
}
int qrk(int x){
	int ans = 1;
	for(int i = 1;i<=qt;i++)ans+=qri(t[que[i]].rid,1,2*N,1,x-1);
	return ans;
}
int nl,nr,nmid,na,nrt[N];
int qrx(int k){
	nl = 1,nr = 2*N,nmid;
	for(int i = 1;i<=qt;i++)nrt[i] = t[que[i]].rid;
	while(nl<nr){
		nmid = (nl+nr)>>1;
		na = 0;
		for(int i = 1;i<=qt;i++)na+=it[it[nrt[i]].ls].sum;
		if(na>=k){
			nr = nmid;
			for(int i = 1;i<=qt;i++)nrt[i] = it[nrt[i]].ls;
		}else{
			k-=na;
			nl = nmid+1;
			for(int i = 1;i<=qt;i++)nrt[i] = it[nrt[i]].rs;
		}
	}
	return lsa[nl];
}
void fd(int l,int r,int x,int op){
	if(nr)return;
	if((r<=x&&op)||(l>=x&&!op)){
		bool fg = 0;
		for(int i = 1;i<=qt;i++)fg|=it[nrt[i]].sum;
		if(!fg)return;
		nr = r;
		nl = l;
		return;
	}
	int mid = (l+r)>>1;
	vector<int> yr;
	for(int i = 1;i<=qt;i++)yr.push_back(nrt[i]);
	if(op){
		if(mid<x){
			for(int i = 1;i<=qt;i++)nrt[i] = it[yr[i-1]].rs;
			fd(mid+1,r,x,op);
		}
		if(!nr){
			for(int i = 1;i<=qt;i++)nrt[i] = it[yr[i-1]].ls;
			fd(l,mid,x,op);
		}
	}else{
		if(mid>=x){
			for(int i = 1;i<=qt;i++)nrt[i] = it[yr[i-1]].ls;
			fd(l,mid,x,op);
		}
		if(!nr){
			for(int i = 1;i<=qt;i++)nrt[i] = it[yr[i-1]].rs;
			fd(mid+1,r,x,op);
		}
	}
}
int qrqh(int x,int op){
	for(int i = 1;i<=qt;i++)nrt[i] = t[que[i]].rid;
	nl = nr = 0;
	if(op)x--;
	else x++;
	fd(1,2*N,x,op);
	if(!nr){
		if(op)return -inf;
		else return inf;
	}
	bool fg;
	while(nl<nr){
		nmid = (nl+nr)>>1;
		fg = 0; 
		if(op){
			for(int i = 1;i<=qt;i++)fg|=it[it[nrt[i]].rs].sum;
			if(fg){
				for(int i = 1;i<=qt;i++)nrt[i] = it[nrt[i]].rs;
				nl = nmid+1;
			}else{
				for(int i = 1;i<=qt;i++)nrt[i] = it[nrt[i]].ls;
				nr = nmid;
			}
		}else{
			for(int i = 1;i<=qt;i++)fg|=it[it[nrt[i]].ls].sum;
			if(fg){
				for(int i = 1;i<=qt;i++)nrt[i] = it[nrt[i]].ls;
				nr = nmid;
			}else{
				for(int i = 1;i<=qt;i++)nrt[i] = it[nrt[i]].rs;
				nl = nmid+1;
			}
		}
	}
	return lsa[nl];
}
int main(){
	it[0].sum = it[0].ls = it[0].rs = 0;
	scanf("%d%d",&n,&m);
	for(int i = 1;i<=n;i++){
		scanf("%d",&a[i]);
		lsa[++ct] = a[i];
	}
	for(int i = 1;i<=m;i++){
		scanf("%d%d%d",&q[i].op,&q[i].l,&q[i].r);
		if(q[i].op!=3){
			scanf("%d",&q[i].k);
			lsa[++ct] = q[i].k;
		}else lsa[++ct] = q[i].r;
	}
	sort(lsa+1,lsa+ct+1);
	ct = unique(lsa+1,lsa+ct+1)-lsa-1;
	for(int i = 1;i<=n;i++)a[i] = rs(a[i]);
	build(1,1,n);
	for(int i = 1;i<=m;i++){
		int op = q[i].op;
		if(op!=3){
			qt = 0;
			split(1,q[i].l,q[i].r);
		}
		if(op<2||op>3)q[i].k = rs(q[i].k);
		if(op==1){
			printf("%d\n",qrk(q[i].k));
		}else if(op==2){
			printf("%d\n",qrx(q[i].k));
		}else if(op==3){
			cgo(1,q[i].l,rs(q[i].r));
		}else if(op==4){
			printf("%d\n",qrqh(q[i].k,1));
		}else printf("%d\n",qrqh(q[i].k,0));
	}
	return 0;
}

对于第76行(qri函数中),写注释里的会MLE在#10

写没有注释掉的,#10 回收节点100MB左右,不回收180MB左右。为什么会这样?对于动态开点线段树,我在函数的参数中记录线段树节点的左右端点,感觉这样即使在p=0时不返回也不会出什么大问题,为什么改一下空间差别那么大

2024/6/16 12:44
加载中...