题解 P6224 【[BJWC2014]数据】
关于KDT最近邻查询方面,前几个星期被@Tweetuski和@142857cs两位巨佬给D得体无完肤(导致现在我看到最近邻就头疼)
具体可见
https://www.luogu.com.cn/discuss/show/214220
https://www.luogu.com.cn/discuss/show/214426
基于对最近邻查询深深的恐惧感,这题我一开始没有用最近邻
首先有
那维护
然后
这把
在类似替罪羊树的重构方面,我也被@142857cs给D了,所以我预先把所有点都记下来,提前建好树形,避免了重构的操作
所以这种方法没用最近邻查询,复杂度是标准的但是出题人很善良的把根号卡掉了)
这是根号的代码,也许有大佬可以帮我卡卡?
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef pair<int,int> Pair;
const int N=4e5+5;
const Pair Em=make_pair(-1e9,-1e9);
#define F first
#define S second
int L[N],R[N],U[N],D[N],ls[N],rs[N],loc[N],fa[N];
int n,q,treesize,rt,cnt,maxx,maxy,Dir,l,r,d,u,k;
Pair poi[N];
bool exi[N];
struct Point{ int x,y,loc; bool E; } p[N];
struct Ques{ int op,x,y,loc; } que[N];
struct Data{ int a[4]; } Da,dat[N];
Data operator + (const Data& a, const Data& b){
Data c;
c.a[0]=min(a.a[0],b.a[0]); c.a[1]=min(a.a[1],b.a[1]);
c.a[2]=min(a.a[2],b.a[2]); c.a[3]=min(a.a[3],b.a[3]);
return c;
}
bool operator < (const Point& a, const Point& b){ return Dir?a.y<b.y:a.x<b.x; }
inline void Mix(Data& D, Pair P){
if (P.F==Em.F && P.S==Em.S) D.a[0]=D.a[1]=D.a[2]=D.a[3]=2e9;
else {
int x=P.F,y=P.S;
D.a[0]=-x-y; D.a[1]=-x+y;
D.a[2]= x-y; D.a[3]= x+y;
}
}
inline void Newnode(int now){
if (!exi[now]) L[now]=U[now]=1e9,R[now]=D[now]=0,Mix(dat[now],Em); else
L[now]=R[now]=poi[now].F,U[now]=D[now]=poi[now].S,Mix(dat[now],poi[now]);
}
inline void pushup(int now){
Newnode(now);
L[now]=min(L[now],min(L[ls[now]],L[rs[now]]));
U[now]=min(U[now],min(U[ls[now]],U[rs[now]]));
R[now]=max(R[now],max(R[ls[now]],R[rs[now]]));
D[now]=max(D[now],max(D[ls[now]],D[rs[now]]));
dat[now]=dat[now]+dat[ls[now]]+dat[rs[now]];
}
void build(int& now, int l, int r, int tag){
if (l>r) return;
int mid=(l+r)>>1; now=++treesize; Dir=tag;
nth_element(p+l,p+mid,p+r+1);
poi[now]=make_pair(p[mid].x,p[mid].y); exi[now]=p[mid].E;
Newnode(now);
if (p[mid].loc) loc[p[mid].loc]=now;
build(ls[now],l,mid-1,tag^1); build(rs[now],mid+1,r,tag^1);
if (ls[now]) fa[ls[now]]=now;
if (rs[now]) fa[rs[now]]=now;
pushup(now);
}
int query(int now){
if (!now) return 2e9;
if (l<=L[now] && R[now]<=r && u<=U[now] && D[now]<=d) return dat[now].a[k];
if (l>R[now] || r<L[now] || u>D[now] || d<U[now]) return 2e9;
int x=poi[now].F,y=poi[now].S,c=2e9;
if (l<=x && x<=r && u<=y && y<=d && exi[now]){
if (k==0) c=-x-y;
else if (k==1) c=-x+y;
else if (k==2) c= x-y;
else c=x+y;
}
return min(c,min(query(ls[now]),query(rs[now])));
}
inline int read(){
int num=0,fu=1; char ch=getchar();
while (ch<'0' || ch>'9') fu&=(ch!='-'),ch=getchar();
while (ch>='0' && ch<='9') num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
return fu?num:-num;
}
int main(){
n=read(); Newnode(0); Da.a[0]=Da.a[1]=Da.a[2]=Da.a[3]=-2e9;
for (int i=1; i<=n; i++){
p[i].x=read(),p[i].y=read(),p[i].E=1;
Da.a[0]=max(Da.a[0],-p[i].x-p[i].y); Da.a[1]=max(Da.a[1],-p[i].x+p[i].y);
Da.a[2]=max(Da.a[2], p[i].x-p[i].y); Da.a[3]=max(Da.a[3], p[i].x+p[i].y);
maxx=max(maxx,p[i].x); maxy=max(maxy,p[i].y);
}
q=read(); cnt=n;
for (int i=1; i<=q; i++){
que[i].op=read(); que[i].x=read(); que[i].y=read();
if (!que[i].op){
cnt++,p[cnt].x=que[i].x,p[cnt].y=que[i].y,p[cnt].loc=que[i].loc=cnt;
maxx=max(maxx,p[cnt].x); maxy=max(maxy,p[cnt].y);
}
}
build(rt,1,cnt,0);
for (int i=1; i<=q; i++){
int x=que[i].x,y=que[i].y;
if (que[i].op==0){
int u=loc[que[i].loc]; exi[u]=1; Newnode(u);
Da.a[0]=max(Da.a[0],-x-y); Da.a[1]=max(Da.a[1],-x+y);
Da.a[2]=max(Da.a[2], x-y); Da.a[3]=max(Da.a[3], x+y);
for (; u; u=fa[u]) pushup(u);
} else
if (que[i].op==1){
int ans=2e9,r1,r2,r3,r4;
l=0,r=x,u=0,d=y,k=0; r1=query(rt);
l=0,r=x,u=y,d=maxy,k=1; r2=query(rt);
l=x,r=maxx,u=0,d=y,k=2; r3=query(rt);
l=x,r=maxx,u=y,d=maxy,k=3; r4=query(rt);
if (r1!=2e9) ans=min(ans,r1+x+y);
if (r2!=2e9) ans=min(ans,r2+x-y);
if (r3!=2e9) ans=min(ans,r3-x+y);
if (r4!=2e9) ans=min(ans,r4-x-y);
printf("%d\n",ans);
} else printf("%d\n",max(max(x+y+Da.a[0],x-y+Da.a[1]),max(-x+y+Da.a[2],-x-y+Da.a[3])));
}
return 0;
}
无奈,上面这份代码卡不过去,所以我又写了一份最近邻查询的版本,下面是代码
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
const int N=5e5+5;
#define F first
#define S second
int L[N],R[N],U[N],D[N],ls[N],rs[N],loc[N],fa[N],Px[N],Py[N];
int n,q,treesize,rt,cnt,maxx,maxy,Dir,l,r,d,u,k,x,y,ans;
bool exi[N];
struct Point{ int x,y,loc; bool E; } p[N];
struct Ques{ int op,x,y,loc; } que[N];
struct Data{ int a[4]; } Da;
bool operator < (const Point& a, const Point& b){ return Dir?a.y<b.y:a.x<b.x; }
inline void Newnode(int now){
if (!exi[now]) L[now]=U[now]=1e9,R[now]=D[now]=0; else
L[now]=R[now]=Px[now],U[now]=D[now]=Py[now];
}
inline void pushup(int now){
Newnode(now);
L[now]=min(L[now],min(L[ls[now]],L[rs[now]]));
U[now]=min(U[now],min(U[ls[now]],U[rs[now]]));
R[now]=max(R[now],max(R[ls[now]],R[rs[now]]));
D[now]=max(D[now],max(D[ls[now]],D[rs[now]]));
}
void build(int& now, int l, int r, int tag){
if (l>r) return;
int mid=(l+r)>>1; now=++treesize; Dir=tag;
nth_element(p+l,p+mid,p+r+1);
Px[now]=p[mid].x; Py[now]=p[mid].y; exi[now]=p[mid].E;
Newnode(now);
if (p[mid].loc) loc[p[mid].loc]=now;
build(ls[now],l,mid-1,tag^1); build(rs[now],mid+1,r,tag^1);
if (ls[now]) fa[ls[now]]=now;
if (rs[now]) fa[rs[now]]=now;
pushup(now);
}
inline int read(){
int num=0,fu=1; char ch=getchar();
while (ch<'0' || ch>'9') fu&=(ch!='-'),ch=getchar();
while (ch>='0' && ch<='9') num=(num<<3)+(num<<1)+ch-'0',ch=getchar();
return fu?num:-num;
}
inline int Get_dis(int now){
if (!now) return 2e9;
int ans=0;
if (x<L[now]) ans+=L[now]-x;
if (y<U[now]) ans+=U[now]-y;
if (x>R[now]) ans+=x-R[now];
if (y>D[now]) ans+=y-D[now];
return ans;
}
void query(int now){
if (!now) return;
if (exi[now]) ans=min(ans,abs(Px[now]-x)+abs(Py[now]-y));
int dl=Get_dis(ls[now]),dr=Get_dis(rs[now]);
if (dl<dr){
if (dl<ans) query(ls[now]);
if (dr<ans) query(rs[now]);
} else {
if (dr<ans) query(rs[now]);
if (dl<ans) query(ls[now]);
}
}
int main(){
n=read(); Newnode(0); Da.a[0]=Da.a[1]=Da.a[2]=Da.a[3]=-2e9;
for (int i=1; i<=n; i++){
p[i].x=read(),p[i].y=read(),p[i].E=1;
Da.a[0]=max(Da.a[0],-p[i].x-p[i].y); Da.a[1]=max(Da.a[1],-p[i].x+p[i].y);
Da.a[2]=max(Da.a[2], p[i].x-p[i].y); Da.a[3]=max(Da.a[3], p[i].x+p[i].y);
maxx=max(maxx,p[i].x); maxy=max(maxy,p[i].y);
}
q=read(); cnt=n;
for (int i=1; i<=q; i++){
que[i].op=read(); que[i].x=read(); que[i].y=read();
if (!que[i].op){
cnt++,p[cnt].x=que[i].x,p[cnt].y=que[i].y,p[cnt].loc=que[i].loc=cnt;
maxx=max(maxx,p[cnt].x); maxy=max(maxy,p[cnt].y);
}
}
build(rt,1,cnt,0);
for (int i=1; i<=q; i++){
x=que[i].x,y=que[i].y;
if (que[i].op==0){
int u=loc[que[i].loc]; exi[u]=1; Newnode(u);
Da.a[0]=max(Da.a[0],-x-y); Da.a[1]=max(Da.a[1],-x+y);
Da.a[2]=max(Da.a[2], x-y); Da.a[3]=max(Da.a[3], x+y);
for (; u; u=fa[u]) pushup(u);
} else
if (que[i].op==1){
ans=2e9; query(rt);
printf("%d\n",ans);
} else printf("%d\n",max(max(x+y+Da.a[0],x-y+Da.a[1]),max(-x+y+Da.a[2],-x-y+Da.a[3])));
}
return 0;
}
最后,我还是要问:KDT最近邻查询最坏到底是多少的?有没有卡到极限的方法?各位巨佬可以私信我(我到现在都没弄明白)