洛谷P3380 【模板】二逼平衡树(树套树)

版权声明:虽然本蒟蒻很菜,但各位dalao转载请注明出处谢谢。 https://blog.csdn.net/xuxiayang/article/details/89276967

D e s c r i p t i o n Description

动态区间第 k k


S o l u t i o n Solution

静态主席树查询使用了前缀和的思想,但是我们如果套在动态的情况下,改一个意味着后面的都要改,我们可以用树状数组来存线段树的前缀和,就可以 w o r k   o u t work\ out


C o d e Code

#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]);
	}
}

猜你喜欢

转载自blog.csdn.net/xuxiayang/article/details/89276967
今日推荐