【洛谷 3380】二逼平衡树

传送门


Problem

写一种数据结构,来维护一个有序数列,其中需要提供以下操作:

  1. 查询 k k 在区间内的排名。
  2. 查询区间内排名为 k k 的值。
  3. 修改某一位值上的数值。
  4. 查询 k k 在区间内的前驱 ( ( 前驱定义为严格小于 x x ,且最大的数,若不存在输出 2147483647 ) -2147483647)
  5. 查询 k k 在区间内的后继 ( ( 后继定义为严格大于 x x ,且最小的数,若不存在输出 2147483647 ) 2147483647)

Solution

这就是树套树的模板题啦。

我用的就是线段树套非旋Treap。

具体做法就是对于线段树的每一个区间节点,都按照这个区间建非旋Treap。

然后询问的时候就按照区间来查询就可以了。

时间复杂度 O ( n log 2 n ) O(n\log ^2n) ,注意空间开大一点。

具体的细节之类的就看代码吧。


Code

#include<ctime>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 5000005
#define inf ((1ll<<31ll)-1)
using namespace std;
int n,m,a[N];
namespace FHQ_Treap
{
	int tot=0,val[N],Size[N],key[N],lc[N],rc[N];
	int newnode(int k)
	{
		val[++tot]=k,key[tot]=rand();
		Size[tot]=1,lc[tot]=rc[tot]=0;
		return tot;
	}
	void split(int root,int &r1,int &r2,int k)
	{
		if(!root)  {r1=r2=0;return;}
		if(val[root]<=k)  r1=root,split(rc[root],rc[r1],r2,k);
		else  r2=root,split(lc[root],r1,lc[r2],k);
		Size[root]=Size[lc[root]]+Size[rc[root]]+1;
	}
	void Merge(int &root,int r1,int r2)
	{
		if(!r1||!r2)  {root=r1+r2;return;}
		if(key[r1]<key[r2])  root=r1,Merge(rc[root],rc[r1],r2);
		else  root=r2,Merge(lc[root],r1,lc[r2]);
		Size[root]=Size[lc[root]]+Size[rc[root]]+1;
	}
	void Insert(int &root,int k)
	{
		int r1=0,r2=0;
		int x=newnode(k);
		split(root,r1,r2,k);
		Merge(r1,r1,x);
		Merge(root,r1,r2);
	}
	void Delete(int &root,int k)
	{
		int r1=0,r2=0,r3=0;
		split(root,r1,r2,k);
		split(r1,r1,r3,k-1);
		Merge(r3,lc[r3],rc[r3]);
		Merge(r1,r1,r3);
		Merge(root,r1,r2);
	}
	int Rank(int root,int k)
	{
		int r1=0,r2=0;
		split(root,r1,r2,k-1);
		int ans=Size[r1];
		Merge(root,r1,r2);
		return ans;
	}
	int kth(int root,int k)
	{
		if(!root)  return 0;
		if(Size[lc[root]]+1==k)  return root;
		if(Size[lc[root]]+1>k)  return kth(lc[root],k);
		return kth(rc[root],k-Size[lc[root]]-1);
	}
	int Prefix(int root,int k)
	{
		int r1=0,r2=0;
		split(root,r1,r2,k-1);
		if(!r1)  return -inf;
		int x=kth(r1,Size[r1]);
		Merge(root,r1,r2);
		return val[x];
	}
	int Suffix(int root,int k)
	{
		int r1=0,r2=0;
		split(root,r1,r2,k);
		if(!r2)  return inf;
		int x=kth(r2,1);
		Merge(root,r1,r2);
		return val[x];
	}
}
using namespace FHQ_Treap;
namespace Segment_Tree
{
	int Root[N];
	#define mid ((l+r)>>1)
	void build(int rt,int l,int r)
	{
		for(int i=l;i<=r;++i)
		  Insert(Root[rt],a[i]);
		if(l==r)  return;
		build(rt<<1,l,mid);
		build(rt<<1|1,mid+1,r);
	}
	void Modify(int rt,int l,int r,int pos,int k)
	{
		Delete(Root[rt],a[pos]);
		Insert(Root[rt],k);
		if(l==r)  return;
		if(pos<=mid)  Modify(rt<<1,l,mid,pos,k);
		else  Modify(rt<<1|1,mid+1,r,pos,k);
	}
	int QueryRank(int rt,int l,int r,int x,int y,int k)
	{
		if(l>=x&&r<=y)  return Rank(Root[rt],k);
		int ans=0;
		if(x<=mid)  ans+=QueryRank(rt<<1,l,mid,x,y,k);
		if(y>mid)  ans+=QueryRank(rt<<1|1,mid+1,r,x,y,k);
		return ans;
	}
	int QueryPrefix(int rt,int l,int r,int x,int y,int k)
	{
		if(l>=x&&r<=y)  return Prefix(Root[rt],k);
		int ans=-inf;
		if(x<=mid)  ans=max(ans,QueryPrefix(rt<<1,l,mid,x,y,k));
		if(y>mid)  ans=max(ans,QueryPrefix(rt<<1|1,mid+1,r,x,y,k));
		return ans;
	}
	int QuerySuffix(int rt,int l,int r,int x,int y,int k)
	{
		if(l>=x&&r<=y)  return Suffix(Root[rt],k);
		int ans=inf;
		if(x<=mid)  ans=min(ans,QuerySuffix(rt<<1,l,mid,x,y,k));
		if(y>mid)  ans=min(ans,QuerySuffix(rt<<1|1,mid+1,r,x,y,k));
		return ans;
	}
	#undef mid
}
using namespace Segment_Tree;
int Querykth(int x,int y,int k)
{
	int l=0,r=1e8;
	while(l<r)
	{
		int mid=(l+r)>>1;
		if(QueryRank(1,1,n,x,y,mid)<k)  l=mid+1;
		else  r=mid;
	}
	return l-1;
}
int main()
{
	srand(time(0));
	int l,r,i,k,op;
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;++i)
	  scanf("%d",&a[i]);
	build(1,1,n);
	for(i=1;i<=m;++i)
	{
		scanf("%d%d%d",&op,&l,&r);
		if(op!=3)  scanf("%d",&k);
		if(op==1)  printf("%d\n",QueryRank(1,1,n,l,r,k)+1);
		else  if(op==2)  printf("%d\n",Querykth(l,r,k));
		else  if(op==3)  Modify(1,1,n,l,r),a[l]=r;
		else  if(op==4)  printf("%d\n",QueryPrefix(1,1,n,l,r,k));
		else  printf("%d\n",QuerySuffix(1,1,n,l,r,k));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_dreams/article/details/89041200
今日推荐