【BZOJ3489】A simple rmq problem(KD-Tree)

\(Description\)

因为是\(OJ\)上的题,就简单点好了。给出一个长度为\(n\)的序列,给出\(M\)个询问:在\([l,r]\)之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大。如果找不到这样的数,则直接输出\(0\)。我会采取一些措施强制在线。


\(Input\)

第一行为两个整数\(N,M\)\(M\)是询问数,\(N\)是序列的长度\((N<=100000,M<=200000)\)

第二行为\(N\)个整数,描述这个序列{ai},其中所有\(1<=a_{i}<=N\)

再下面\(M\)行,每行两个整数\(x,y\)

询问区间\([l,r]\)由下列规则产生(\(OIER\)都知道是怎样的吧>_<):

\(l=min((x+lastans)\% n+1,(y+lastans)\% n+1);\)

\(r=max((x+lastans)\% n+1,(y+lastans)\% n+1);\)

\(Lastans\)表示上一个询问的答案,一开始\(lastans\)\(0\)


\(Output\)

一共\(M\)行,每行给出每个询问的答案。


\(Sample\) \(Input\)

10 10
6 4 9 10 9 10 9 4 10 4
3 8
10 1
3 4
9 4
8 1
7 8
2 9
1 1
7 3
9 9


\(Sample\) \(Output\)

4
10
10
0
0
10
0
4
0
4


\(Source\)

 练习题 树9-2-树套树

思路

对于这道题,我们首先考虑如何处理 \(“\)[l,r]\(区间内只出现一次”\) 这个限制,我们两次循环处理出每个 \(i\) 位置 \(a_{i}\) 上次和下次出现的位置的 \(pre\)\(nxt\) ,也就是说,对于这个数\(a_{i}\),只出现一次的区间是\([pre[a[i]],nxt[a[i]]]\)

于是,我们将每个位置 \(i\) 看成一个点 \((i,pre[i],nxt[i])\) ,这样,问题就转化为,求一个长方体中包含的点的最大值,这个问题我们用\(KD-Tree\)来解决

当然,你在做题过程中很大几率会碰到\(TLE\)的情况,遇到这种情况,你可以考虑:

  1. 各种卡常奇技淫巧
  2. 将结构体套结构体换为一个结构体
  3. \(KD-Tree\)查询时进行优化

详见丑陋的代码

\(p.s:\) 代码写太丑排版挂掉了,建议 \(ctrl+c\)\(ctrl+v\) 到编译器上食用

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
int n,m,nodetot=0,WD;
int a[N];
int pre[N],nxt[N];
int st[N];
struct point
{
	int x[3],val;
	bool operator <(const point & b) const
	{
		if(x[WD]==b.x[WD])
		{
			if(x[(WD+1)%3]==b.x[(WD+1)%3])return x[(WD+2)%3]<b.x[(WD+2)%3];
			return x[(WD+1)%3]<b.x[(WD+1)%3];
		}
		return x[WD]<b.x[WD];
	} 
}p[N];
struct tree
{
	int siz,lc,rc,maxn,maxx[3],minn[3];
	point pt;
}t[N];
inline void update(int k)
{
	t[k].siz=t[t[k].lc].siz+t[t[k].rc].siz+1;
	t[k].maxn=max(t[k].pt.val,max(t[t[k].lc].maxn,t[t[k].rc].maxn));
	for(int i=0;i<3;i++)
	{
		t[k].maxx[i]=t[k].minn[i]=t[k].pt.x[i];
		if(t[k].lc)
		{
			t[k].maxx[i]=max(t[k].maxx[i],t[t[k].lc].maxx[i]);
			t[k].minn[i]=min(t[k].minn[i],t[t[k].lc].minn[i]);
		}
		if(t[k].rc)
		{
			t[k].maxx[i]=max(t[k].maxx[i],t[t[k].rc].maxx[i]);
			t[k].minn[i]=min(t[k].minn[i],t[t[k].rc].minn[i]);
		}
	}
}
int build(int l,int r,int wd)
{
	if(l>r)return 0;
	int mid=(l+r)>>1,k=++nodetot;
	WD=wd;
	nth_element(p+l,p+mid,p+r+1);
	t[k].pt=p[mid];
	t[k].lc=build(l,mid-1,(wd+1)%3);
	t[k].rc=build(mid+1,r,(wd+1)%3);
	update(k);
	return k;
}

inline bool in(int l1,int r1,int l2,int r2,int l3,int r3,int mn1,int mx1,int mn2,int mx2,int mn3,int mx3)
{
	return mn1>=l1&&mx1<=r1&&mn2>=l2&&mx2<=r2&&mn3>=l3&&mx3<=r3;
}

inline bool out(int l1,int r1,int l2,int r2,int l3,int r3,int mn1,int mx1,int mn2,int mx2,int mn3,int mx3)
{
	return mn1>r1||mx1<l1||mn2>r2||mx2<l2||mn3>r3||mx3<l3;
}

int query(int l1,int r1,int l2,int r2,int l3,int r3,int k)
{
	if(in(l1,r1,l2,r2,l3,r3,t[k].minn[0],t[k].maxx[0],t[k].minn[1],t[k].maxx[1],t[k].minn[2],t[k].maxx[2]))return t[k].maxn;	
	int res=0;
	if(in(l1,r1,l2,r2,l3,r3,t[k].pt.x[0],t[k].pt.x[0],t[k].pt.x[1],t[k].pt.x[1],t[k].pt.x[2],t[k].pt.x[2]))res=t[k].pt.val;
	if(t[t[k].lc].maxn>t[t[k].rc].maxn)//就是这个优化
	{
		if(t[k].lc&&t[t[k].lc].maxn>res&&!out(l1,r1,l2,r2,l3,r3,t[t[k].lc].minn[0],t[t[k].lc].maxx[0],t[t[k].lc].minn[1],t[t[k].lc].maxx[1],t[t[k].lc].minn[2],t[t[k].lc].maxx[2]))res=max(res,query(l1,r1,l2,r2,l3,r3,t[k].lc));
		if(t[k].rc&&t[t[k].rc].maxn>res&&!out(l1,r1,l2,r2,l3,r3,t[t[k].rc].minn[0],t[t[k].rc].maxx[0],t[t[k].rc].minn[1],t[t[k].rc].maxx[1],t[t[k].rc].minn[2],t[t[k].rc].maxx[2]))res=max(res,query(l1,r1,l2,r2,l3,r3,t[k].rc));
	}
	else 
	{
		if(t[k].rc&&t[t[k].rc].maxn>res&&!out(l1,r1,l2,r2,l3,r3,t[t[k].rc].minn[0],t[t[k].rc].maxx[0],t[t[k].rc].minn[1],t[t[k].rc].maxx[1],t[t[k].rc].minn[2],t[t[k].rc].maxx[2]))res=max(res,query(l1,r1,l2,r2,l3,r3,t[k].rc));
		if(t[k].lc&&t[t[k].lc].maxn>res&&!out(l1,r1,l2,r2,l3,r3,t[t[k].lc].minn[0],t[t[k].lc].maxx[0],t[t[k].lc].minn[1],t[t[k].lc].maxx[1],t[t[k].lc].minn[2],t[t[k].lc].maxx[2]))res=max(res,query(l1,r1,l2,r2,l3,r3,t[k].lc));
	}
	return res;
}

inline int read()
{
	int x=0;
	char ch=getchar();
	while(!isdigit(ch))ch=getchar();
	while(isdigit(ch))
	{
		x=(x<<3)+(x<<1)+(ch^48);
		ch=getchar();
	}
	return x;
}

int main()
{
	n=read(),m=read();
	for(register int i=1;i<=n;i++)a[i]=read();
	for(register int i=1;i<=n;i++)
		pre[i]=st[a[i]],st[a[i]]=i;
	for(register int i=1;i<=n;i++)st[a[i]]=n+1;
	for(register int i=n;i>=1;i--)
		nxt[i]=st[a[i]],st[a[i]]=i;
	for(register int i=1;i<=n;i++)
		p[i].x[0]=i,p[i].x[1]=pre[i],p[i].x[2]=nxt[i],p[i].val=a[i];
	build(1,n,0);
	int lastans=0;
	int x,y,l,r;
	for(register int i=1;i<=m;i++)
	{
		x=read(),y=read();
		x=(x+lastans)%n,y=(y+lastans)%n;x++,y++;
		l=min(x,y),r=max(x,y);
		printf("%d\n",lastans=query(l,r,0,l-1,r+1,n+1,1));
	}
	return 0;
}
posted @ 2020-01-15 19:43  ShuraEye  阅读(112)  评论(0编辑  收藏  举报