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


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