【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\)的情况,遇到这种情况,你可以考虑:
- 各种卡常奇技淫巧
- 将结构体套结构体换为一个结构体
- 在\(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;
}