我以前可能写了个假的KD-Tree,关键是还过了这么多题。。。
题目链接
给出一个长度为n的序列,给出M个询问:在[l,r]之间只出现过一次的数的最大值。要求在线,找不到输出0.
确定了一个上一次出现和下一次出现的位置之后,就是在一个三元组内查询最值,那么就上KD-Tree即可。
#include
#include
#include
#include
#include
#include
#include
using namespace std;
const int maxn=100000+105,maxm=200000+105;
int n,m,a[maxn],lastans=0,ret;
int pos[maxn];
int D;
struct data{
int d[3],w;//l,r是实际有效闭区间
friend bool operator<(data a,data b)
{
return a.d[D]struct KD_Tree
{
int rt,np,lc[maxn],rc[maxn],mx[maxn][3],mi[maxn][3],maxv[maxn];
void pushup(int now)
{
if(lc[now])
{
maxv[now]=max(maxv[now],maxv[lc[now]]);
for(int i=0;i<3;i++)
{
mx[now][i]=max(mx[now][i],mx[lc[now]][i]);
mi[now][i]=min(mi[now][i],mi[lc[now]][i]);
}
}
if(rc[now])
{
maxv[now]=max(maxv[now],maxv[rc[now]]);
for(int i=0;i<3;i++)
{
mx[now][i]=max(mx[now][i],mx[rc[now]][i]);
mi[now][i]=min(mi[now][i],mi[rc[now]][i]);
}
}
}
int Newnode(int x)
{
++np;
maxv[np]=p[x].w;
for(int i=0;i<3;i++)
mx[np][i]=mi[np][i]=p[x].d[i];
return np;
}
void Build(int &now,int L,int R,int k)
{
if(L>R)return;
int m=(L+R)>>1;
D=k;
nth_element(p+L,p+m,p+R+1);
now=Newnode(m);
Build(lc[now],L,m-1,(k+1)%3);
Build(rc[now],m+1,R,(k+1)%3);
pushup(now);
}
bool calc1(int now,data i,data j)//如果now完全在ij外就返回1
{
for(int k=0;k<3;k++)
{
if(mx[now][k]return 1;
}
return 0;
}
bool calc2(int now,data i,data j)//如果i,j包含了now就返回1
{
for(int k=0;k<3;k++)
{
if(!(i.d[k]<=mi[now][k] && mx[now][k]<=j.d[k]))
return 0;
}
return 1;
}
bool calc(data x,data i,data j)
{
for(int k=0;k<3;k++)
{
if(!(i.d[k]<=x.d[k] && x.d[k]<=j.d[k]))
return 0;
}
return 1;
}
void query(int now,int L,int R,data i,data j)
{
if(!now)return;
if(maxv[now]<=ret)return;
if(calc1(now,i,j))return;
if(calc2(now,i,j)){ret=maxv[now];return;}
int m=(L+R)>>1;
if(calc(p[m],i,j))
ret=max(ret,p[m].w);
if(maxv[lc[now]]>maxv[rc[now]])
{
query(lc[now],L,m-1,i,j);
query(rc[now],m+1,R,i,j);
}
else
{
query(rc[now],m+1,R,i,j);
query(lc[now],L,m-1,i,j);
}
}
}kd;
void Init()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
p[i].w=a[i];
p[i].d[2]=i;
p[i].d[0]=pos[a[i]]+1;
pos[a[i]]=i;
}
for(int i=1;i<=n;i++)pos[i]=n+1;
for(int i=n;i;i--)
{
p[i].d[1]=pos[a[i]]-1;
pos[a[i]]=i;
}
kd.Build(kd.rt,1,n,0);
}
void query()
{
int x,y,L,R;
while(m--)
{
scanf("%d%d",&x,&y);
L=min((x+lastans)%n+1,(y+lastans)%n+1);
R=max((x+lastans)%n+1,(y+lastans)%n+1);
ret=0;
data i,j;
i.d[0]=0,j.d[0]=L;
i.d[1]=R,j.d[1]=n+1;
i.d[2]=L,j.d[2]=R;
kd.query(kd.rt,1,n,i,j);
lastans=ret;
printf("%d\n",ret);
}
}
int main()
{
Init();
query();
return 0;
}