【bzoj4571】[Scoi2016]美味 主席树

只能想出个大概
没有加法是主席树
有了加法对应的就是主席树上一个区间而不是一个儿子了
查询的时候,并不是在主席树上查询,而只是一种线段树式的查询
如果+x后[l,mid]或[mid+1,r]有数,则往对应方向走
查询[l,mid]和[mid+1,r]就在主席树上查询
左儿子[l,mid]对应了区间[l-x,mid-x]
右儿子[mid+1,r]对应了区间[mid+1-x,r-x]

一共会二分logn次,一次查询复杂度为O(logn),总复杂度O(mlog^2n)


#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
#define maxn 200010
#define N 6000010
#define mx (1<<19)-1

using namespace std;

int root[maxn],lch[N],rch[N],size[N];
int n,T,tot;

int modify(int pre,int l,int r,int x)
{
	int now=++tot;
	if (l==r)
	{
		lch[now]=rch[now]=0;size[now]=size[pre]+1;
	}
	else
	{
		int mid=(l+r)/2;
		if (x<=mid)
		{
			lch[now]=modify(lch[pre],l,mid,x);rch[now]=rch[pre];
		}
		else
		{
			rch[now]=modify(rch[pre],mid+1,r,x);lch[now]=lch[pre];
		}
		size[now]=size[lch[now]]+size[rch[now]];
	}
	return now;
}

int Query(int root1,int root2,int l,int r,int L,int R)
{
	if (L<=l && r<=R) return size[root2]-size[root1];
	int mid=(l+r)/2,ans=0;
	if (L<=mid) ans+=Query(lch[root1],lch[root2],l,mid,L,R);
	if (mid<R) ans+=Query(rch[root1],rch[root2],mid+1,r,L,R);
	return ans;
}

int query(int i,int l,int r,int L,int R,int b,int x)
{
	if (l==r) return l^b;
	int mid=(l+r)/2,D=((b>>i)&1);
	if (D==1)
	{
		if (mid-x<0) return query(i-1,mid+1,r,L,R,b,x);
		if (Query(root[L-1],root[R],0,mx,max(l-x,0),max(mid-x,0))) return query(i-1,l,mid,L,R,b,x);
		else return query(i-1,mid+1,r,L,R,b,x);
	}
	else
	{
		if (mid-x<0) return query(i-1,mid+1,r,L,R,b,x);
		if (Query(root[L-1],root[R],0,mx,max(mid+1-x,0),max(r-x,0))) return query(i-1,mid+1,r,L,R,b,x);
		else return query(i-1,l,mid,L,R,b,x);
	}
}

int main()
{
	scanf("%d%d",&n,&T);
	root[0]=lch[0]=rch[0]=size[0]=0;
	for (int i=1;i<=n;i++)
	{
		int x;
		scanf("%d",&x);
		root[i]=modify(root[i-1],0,mx,x);
	}
	while (T--)
	{
		int b,x,l,r;
		scanf("%d%d%d%d",&b,&x,&l,&r);
		printf("%d\n",query(18,0,mx,l,r,b,x));
	}
	return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章