版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/89276967
动态区间第 大
静态主席树查询使用了前缀和的思想,但是我们如果套在动态的情况下,改一个意味着后面的都要改,我们可以用树状数组来存线段树的前缀和,就可以 了
#include<cstdio>
#include<cctype>
#include<algorithm>
#define N 50010
#define inf 2147483647
using namespace std;
int T[N],sum[N<<8],L[N<<8],R[N<<8],a[N],b[N<<1],n,m,cnt,q,x[N],y[N],lx,ly;
inline long long read()
{
char c;int f=0,d=1;
while(c=getchar(),!isdigit(c)) if(c=='-') d=-1;f=(f<<3)+(f<<1)+c-48;
while(c=getchar(),isdigit(c)) f=(f<<3)+(f<<1)+c-48;
return d*f;
}
inline void ins(int &k,int x,int d,int l=1,int r=m)//在以k为根的这个数对x这个值+d
{
if(!k) k=++cnt;sum[k]+=d;if(l==r) return;
int mid=l+r>>1;
if(x<=mid) ins(L[k],x,d,l,mid);//在左边
else ins(R[k],x,d,mid+1,r);//在右边
return;
}
inline void modify(int x,int d)//对由前x个数构成的线段树+d
{
int t=lower_bound(b+1,b+1+m,a[x])-b;
for(register int i=x;i<=n;i+=i&-i) ins(T[i],t,d);
return;
}
inline void getsum(int &s)//处理在T[r]-R[l-1]后这个节点上的值
{
for(register int i=1;i<=lx;i++)s-=sum[L[x[i]]];
for(register int i=1;i<=ly;i++)s+=sum[L[y[i]]];
return;
}
inline void getls()//表示节点往左走
{
for(register int i=1;i<=lx;i++) x[i]=L[x[i]];
for(register int i=1;i<=ly;i++) y[i]=L[y[i]];
return;
}
inline void getrs()//表示节点往右走
{
for(register int i=1;i<=lx;i++) x[i]=R[x[i]];
for(register int i=1;i<=ly;i++) y[i]=R[y[i]];
return;
}
inline void prepare(int p,int q)//预处理
{
lx=ly=0;
for(register int i=p-1;i;i-=i&-i) x[++lx]=T[i];//把p-1预处理给x
for(register int i=q;i;i-=i&-i) y[++ly]=T[i];//把q预处理给y
return;
}
inline int find_kth(int k,int l=1,int r=m)//查询区间第k大
{
if(l==r) return l;int mid=l+r>>1,s=0;
getsum(s);
if(s>=k) {getls();return find_kth(k,l,mid);}
getrs();return find_kth(k-s,mid+1,r);
}
inline void Find_kth(int l,int r,int k)//回答区间第k大
{
prepare(l,r);
printf("%d\n",b[find_kth(k)]);
}
inline int get_rank(int k,int x,int l=1,int r=m)//查询排名为k的数
{
if(!k) return 0;if(l==r) {if(x==l) return 0;return sum[k];}
int mid=l+r>>1;
if(x<=mid) return get_rank(L[k],x,l,mid);//类似BST的操作
return sum[L[k]]+get_rank(R[k],x,mid+1,r);
}
inline void Get_rank(int l,int r,int x) //回答x的排名
{
int s=0,t=lower_bound(b+1,b+1+m,x)-b;
for(register int i=l-1;i;i-=i&-i) s-=get_rank(T[i],t);
for(register int i=r;i;i-=i&-i) s+=get_rank(T[i],t);
printf("%d\n",s+1);
return;
}
inline void Get_pre(int l,int r,int x)//回答x的前驱
{
int s=0,t=lower_bound(b+1,b+1+m,x)-b;
for(register int i=l-1;i;i-=i&-i) s-=get_rank(T[i],t);
for(register int i=r;i;i-=i&-i) s+=get_rank(T[i],t);
if(!s) printf("%d\n",-inf);
else Find_kth(l,r,s);
return;
}
inline void Get_nxt(int l,int r,int x)//回答x的后继
{
int s=0,t=lower_bound(b+1,b+1+m,x)-b+1;
for(register int i=l-1;i;i-=i&-i) s-=get_rank(T[i],t);
for(register int i=r;i;i-=i&-i) s+=get_rank(T[i],t);
if(s>r-l) printf("%d\n",inf);
else Find_kth(l,r,s+1);
return;
}
int op[N],ql[N],qr[N],qk[N];
signed main()
{
m=n=read();q=read();
for(register int i=1;i<=n;i++) a[i]=read(),b[i]=a[i];
for(register int i=1;i<=q;i++)
{
op[i]=read();ql[i]=read();qr[i]=read();
if(op[i]!=3) qk[i]=read();
if(op[i]==3) b[++m]=qr[i];
else if(op[i]!=2) b[++m]=qk[i];
}
sort(b+1,b+m+1);m=unique(b+1,b+m+1)-b-1;
for(register int i=1;i<=n;i++) modify(i,1);
for(register int i=1;i<=q;i++)
{
if(op[i]==1) Get_rank(ql[i],qr[i],qk[i]);
if(op[i]==2) Find_kth(ql[i],qr[i],qk[i]);
if(op[i]==3) modify(ql[i],-1),a[ql[i]]=qr[i],modify(ql[i],1);
if(op[i]==4) Get_pre(ql[i],qr[i],qk[i]);
if(op[i]==5) Get_nxt(ql[i],qr[i],qk[i]);
}
}