P3380 二逼平衡树 [树状数组套可持久化主席树]

( ext{Description})

( ext{Sample})

( ext{Input})

8 10
93193828 87467295 7194563 77236060 94622726 47450113 70878734 52950301 
2 6 8 2
5 4 6 89104605
3 7 62289938
3 4 94396652
4 7 7 36968499
4 8 8 42956931
4 1 2 30670581
5 7 7 7587866
1 7 7 74144921
1 3 3 53352412

( ext{Output})

52950301
94622726
-2147483647
-2147483647
-2147483647
62289938
2
2

( ext{Solution})

主要是有修改操作,普通的持久化主席树因为类似一个前缀和,只能 (mathcal O(nlog n)) 修改一次。类似优化前缀和,我们可以用树状数组优化主席树。

注意一下:树状数组优化实质上是优化下标的选取。

所以可持久化主席树是以 (l-1,r) 下标建的树做差,树状数组套可持久化主席树就是以 ((l-1,l-1-lowbit(l-1),...),(r,r-lowbit(r)...)) 下标建的树做差。

我们预处理出上面那一坨下标对应的树的根,在各种函数中相减就行了。

总时间复杂度 (mathcal O(n log^2 n))

( ext{Code})

#include <cstdio>

#define rep(i,_l,_r) for(register signed i=(_l),_end=(_r);i<=_end;++i)
#define fep(i,_l,_r) for(register signed i=(_l),_end=(_r);i>=_end;--i)
#define erep(i,u) for(signed i=head[u],v=to[i];i;i=nxt[i],v=to[i])
#define efep(i,u) for(signed i=Head[u],v=to[i];i;i=nxt[i],v=to[i])
#define print(x,y) write(x),putchar(y)

template <class T> inline T read(const T sample) {
    T x=0; int f=1; char s;
    while((s=getchar())>'9'||s<'0') if(s=='-') f=-1;
    while(s>='0'&&s<='9') x=(x<<1)+(x<<3)+(s^48),s=getchar();
    return x*f;
}
template <class T> inline void write(const T x) {
    if(x<0) return (void) (putchar('-'),write(-x));
    if(x>9) write(x/10);
    putchar(x%10^48);
}
template <class T> inline T Max(const T x,const T y) {if(x>y) return x; return y;}
template <class T> inline T Min(const T x,const T y) {if(x<y) return x; return y;}
template <class T> inline T fab(const T x) {return x>0?x:-x;}
template <class T> inline T gcd(const T x,const T y) {return y?gcd(y,x%y):x;}
template <class T> inline T lcm(const T x,const T y) {return x/gcd(x,y)*y;}
template <class T> inline T Swap(T &x,T &y) {x^=y^=x^=y;}

#include <algorithm>
using namespace std;

const int inf=2147483647,maxn=5e4+5;

int n,m,a[maxn],b[maxn<<1],tot,sz,son[maxn*16*16][2],siz[maxn*16*16],rt[maxn],x[maxn],y[maxn],l[maxn],r[maxn];

int lowbit(int x) {return x&-x;}

int modify(int pre,int l,int r,int p,int k) {
	int x=++sz;
	son[x][0]=son[pre][0],son[x][1]=son[pre][1],siz[x]=siz[pre]+k;
	if(l==r) return x;
	int mid=l+r>>1;
	if(p<=mid) son[x][0]=modify(son[pre][0],l,mid,p,k);
	else son[x][1]=modify(son[pre][1],mid+1,r,p,k);
	return x;
}

void add(int i,int k) {
	int x=i;
	while(x<=n) rt[x]=modify(rt[x],1,tot,a[i],k),x+=lowbit(x);//注意这里是从自己开始更改而不是从上一个更改,毕竟已经不是前缀和了
}

void init(int i) {
	x[0]=y[0]=0;
	for(int p=l[i]-1;p;p-=lowbit(p)) x[++x[0]]=rt[p];
	for(int p=r[i];p;p-=lowbit(p)) y[++y[0]]=rt[p];
}

int rank(int l,int r,int k) {//这个函数实际上是查 k 前面有多少个数
	if(l==r) return 0;
	int mid=l+r>>1;
	if(k<=mid) {
		rep(i,1,x[0]) x[i]=son[x[i]][0];
		rep(i,1,y[0]) y[i]=son[y[i]][0];
		return rank(l,mid,k);
	}
	int ret=0;
	rep(i,1,x[0]) ret-=siz[son[x[i]][0]],x[i]=son[x[i]][1];
	rep(i,1,y[0]) ret+=siz[son[y[i]][0]],y[i]=son[y[i]][1];
	return rank(mid+1,r,k)+ret;
}

int kth(int l,int r,int k) {
	if(l==r) return b[l];
	int mid=l+r>>1,ret=0;
	rep(i,1,x[0]) ret-=siz[son[x[i]][0]];
	rep(i,1,y[0]) ret+=siz[son[y[i]][0]];
	if(ret>=k) {
		rep(i,1,x[0]) x[i]=son[x[i]][0];
		rep(i,1,y[0]) y[i]=son[y[i]][0];
		return kth(l,mid,k);
	}
	rep(i,1,x[0]) x[i]=son[x[i]][1];
	rep(i,1,y[0]) y[i]=son[y[i]][1];
	return kth(mid+1,r,k-ret);
}

int main() {
	int op[maxn],k[maxn];
	n=read(9),m=read(9);
	rep(i,1,n) a[i]=b[i]=read(9);
	tot=n;
	rep(i,1,m) {
		op[i]=read(9),l[i]=read(9),r[i]=read(9);
		if(op[i]^3) k[i]=read(9);
		else b[++tot]=r[i];
		if((op[i]^2)&&(op[i]^3)) b[++tot]=k[i];
	}
	sort(b+1,b+tot+1);
	tot=unique(b+1,b+tot+1)-b-1;
	rep(i,1,n) {
		a[i]=lower_bound(b+1,b+tot+1,a[i])-b;
		add(i,1);
	}
	rep(i,1,m) {
		if(op[i]^3) init(i);
		if((op[i]^2)&&(op[i]^3)) k[i]=lower_bound(b+1,b+tot+1,k[i])-b;
		if(op[i]==1) print(rank(1,tot,k[i])+1,'
');
		if(op[i]==2) print(kth(1,tot,k[i]),'
');
		if(op[i]==3) add(l[i],-1),a[l[i]]=lower_bound(b+1,b+tot+1,r[i])-b,add(l[i],1);
		if(op[i]==4) {
			int t=rank(1,tot,k[i]);
			if(!t) print(-inf,'
');
			else init(i),print(kth(1,tot,t),'
');
		}
		if(op[i]==5) {
			int t=rank(1,tot,k[i]+1);
			if(t>=r[i]-l[i]+1) print(inf,'
');
			else init(i),print(kth(1,tot,t+1),'
');
		}
	}
	return 0;
}
原文地址:https://www.cnblogs.com/AWhiteWall/p/13656147.html