【BZOJ3489】A simple rmq problem(kd-tree)

先考虑怎么样才能保证某个数只出现了一次。

对于序列中的某个数 \(a[i]\),我们求出上一个出现 \(a[i]\) 的位置为 \(pre[i]\),下一个出现 \(a[i]\) 的位置为 \(nxt[i]\)

那么当询问的 \(l\)\(r\) 满足 \(pre[i]<l\leqslant i\)\(i\leqslant r<nxt[i]\) 时,就会有 \(a[i]\) 这个数在区间 \([l,r]\) 内只出现过一次。

所以我们对于每一个 \(i\),把 \((i,pre[i],nxt[i])\) 当作一个三维坐标,用 \(kd-tree\) 维护即可。

\(TLE\) 了怎么办?

  1. \(Point\) 从结构体里拉出来。

  2. \(cmp\) 按我的写法改一下

  3. \(build\) 按我的写法改一下(直接把 \(mid\) 当作当前点的编号)

  4. \(query\) 时判断一下先去左儿子还是右儿子。

希望对你有帮助。

代码和注释如下:

#include<bits/stdc++.h>

#define N 200010

using namespace std;

int D;

struct Point
{
	int num[3],val;
	Point(){};
	Point(const int x,const int y,const int z,const int vall)
	{
		num[0]=x,num[1]=y,num[2]=z,val=vall;
	}
	bool operator < (const Point &b) const
	{
		if(num[D]==b.num[D])
		{
			if(num[(D+1)%3]==b.num[(D+1)%3]) return num[(D+2)%3]<b.num[(D+2)%3];
			return num[(D+1)%3]<b.num[(D+1)%3];
		}
		return num[D]<b.num[D];
	}
}p[N];

struct Tree
{
	int ch[2],maxn[3],minn[3],maxval;
	Point x;
}t[N];

int n,m,a[N];
int root,node;
int last[N],pre[N],nxt[N];
int l,r,ans;

void up(const int u)
{
	for(register int i=0;i<3;i++)
	{
		t[u].maxn[i]=t[u].minn[i]=t[u].x.num[i];
		if(t[u].ch[0])
		{
			t[u].maxn[i]=max(t[u].maxn[i],t[t[u].ch[0]].maxn[i]);
			t[u].minn[i]=min(t[u].minn[i],t[t[u].ch[0]].minn[i]);
		}
		if(t[u].ch[1])
		{
			t[u].maxn[i]=max(t[u].maxn[i],t[t[u].ch[1]].maxn[i]);
			t[u].minn[i]=min(t[u].minn[i],t[t[u].ch[1]].minn[i]);
		}
	}
	t[u].maxval=max(t[u].x.val,max(t[t[u].ch[0]].maxval,t[t[u].ch[1]].maxval));
}

void build(int &mid,const int l,const int r,const int d)
{
	if(l>r) return;
	mid=(l+r)>>1;
	D=d,nth_element(p+l,p+mid,p+r+1);
	t[mid].x=p[mid];
	build(t[mid].ch[0],l,mid-1,(d+1)%3);
	build(t[mid].ch[1],mid+1,r,(d+1)%3);
	up(mid);
}

void query(const int u)
{
	if(!u) return;
	if(l<t[u].minn[1]||l>t[u].maxn[0]||r<t[u].minn[0]||r>t[u].maxn[2]||t[u].maxval<ans) return;
	if(l>=t[u].maxn[1]&&l<=t[u].minn[0]&&r>=t[u].maxn[0]&&r<=t[u].minn[2])
	{
		ans=max(ans,t[u].maxval);
		return;
	}
	if(l>=t[u].x.num[1]&&l<=t[u].x.num[0]&&r>=t[u].x.num[0]&&r<=t[u].x.num[2]) ans=max(ans,t[u].x.val);
	query(t[u].ch[0]);
	query(t[u].ch[1]);
}

inline void read(int &x)
{
	x=0;
	int f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-')f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	x*=f;
}

int main()
{
	read(n),read(m);
	for(register int i=1;i<=n;i++)
	{
		read(a[i]);
		pre[i]=last[a[i]]+1;
		nxt[last[a[i]]]=i-1;
		last[a[i]]=i;
	}
	for(register int i=1;i<=n;i++)
		p[i]=Point(i,pre[i],nxt[i]?nxt[i]:n,a[i]);
	build(root,1,n,0);
	while(m--)
	{
		read(l),read(r);
		l=(l+ans)%n+1,r=(r+ans)%n+1;
		ans=0;
		if(l>r) swap(l,r);
		query(root);
		printf("%d\n",ans);
	}
	return 0;
}
posted @ 2022-10-28 19:40  ez_lcw  阅读(9)  评论(0)    收藏  举报