( 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;
}