题目:
题解:
这题目一眼KD-tree啊,写了一发A了,等等我不是要练cdq分治吗
然后又写了cdq分治,其实不管对于这两个的哪个都是模板题啦
KD-tree:真·模板题
cdq分治:
首先考虑如果只要求一个点左下角与它最近的点有多远
设给定的点为(x,y),左下角有某个点(u,v)
就是要求(x-u)+(y-v)最小。
也就是要求(x+y)-(u+v)最小。
现在整理一下条件:
1.出现时间在它前面
2.x坐标小于它
3.y坐标小于它
维护一个可以查询前缀最大值的树状数组
按时间排序,按x分治
以y为关键字将(x+y)加入树状数组
通过坐标变换,做4遍就可以得到答案
把初始的那些点看成是在0时刻加入的点
这种把初始存在的东西看成操作的思路也很常见
但是KD-tree的要快,是不是我cdq分治写的太丑了?
代码:
KD-tree
#include <cstdio>
#include <iostream>
#include <algorithm>
#define INF 1e9
using namespace std;
const int N=1000005;
struct hh{int mn[2],mx[2],d[2],l,r,id;}t[N];
int cmpd,x,y,n,root,ans,m;
int cmp(const hh &a,const hh &b){return ( (a.d[cmpd]<a.d[cmpd]) || (a.d[cmpd]==a.d[cmpd] && a.d[!cmpd]<b.d[!cmpd]));}
void updata(int now)
{
int lc=t[now].l,rc=t[now].r;
if (lc)
{
t[now].mn[0]=min(t[now].mn[0],t[lc].mn[0]);
t[now].mn[1]=min(t[now].mn[1],t[lc].mn[1]);
t[now].mx[0]=max(t[now].mx[0],t[lc].mx[0]);
t[now].mx[1]=max(t[now].mx[1],t[lc].mx[1]);
}
if (rc)
{
t[now].mn[0]=min(t[now].mn[0],t[rc].mn[0]);
t[now].mn[1]=min(t[now].mn[1],t[rc].mn[1]);
t[now].mx[0]=max(t[now].mx[0],t[rc].mx[0]);
t[now].mx[1]=max(t[now].mx[1],t[rc].mx[1]);
}
}
int build(int l,int r,int d)
{
cmpd=d;
int mid=(l+r)>>1;
nth_element(t+l+1,t+mid+1,t+r+1,cmp);
t[mid].mn[0]=t[mid].mx[0]=t[mid].d[0];
t[mid].mn[1]=t[mid].mx[1]=t[mid].d[1];
if (l!=mid) t[mid].l=build(l,mid-1,!d);
if (r!=mid) t[mid].r=build(mid+1,r,!d);
updata(mid); return mid;
}
void insert(int neww)
{
int D,now;
D=0; now=root;
while (1)
{
t[now].mn[0]=min(t[now].mn[0],t[neww].mn[0]);
t[now].mn[1]=min(t[now].mn[1],t[neww].mn[1]);
t[now].mx[0]=max(t[now].mx[0],t[neww].mx[0]);
t[now].mx[1]=max(t[now].mx[1],t[neww].mx[1]);
if (t[neww].d[D]>=t[now].d[D])
{
if (!t[now].r) {t[now].r=neww;break;}
else now=t[now].r;
}else
{
if (!t[now].l) {t[now].l=neww;break;}
else now=t[now].l;
}
D=!D;
}
}
int dis(int now)
{
int ans=0;
if (x<t[now].mn[0]) ans+=t[now].mn[0]-x;
if (x>t[now].mx[0]) ans+=x-t[now].mx[0];
if (y<t[now].mn[1]) ans+=t[now].mn[1]-y;
if (y>t[now].mx[1]) ans+=y-t[now].mx[1];
return ans;
}
void ask(int now)
{
int d0,dl,dr;
d0=abs(t[now].d[0]-x)+abs(t[now].d[1]-y);
if (d0<ans) ans=d0;
if (t[now].l) dl=dis(t[now].l);else dl=INF;
if (t[now].r) dr=dis(t[now].r);else dr=INF;
if (dl<dr)
{
if (dl<ans) ask(t[now].l);
if (dr<ans) ask(t[now].r);
}else
{
if (dr<ans) ask(t[now].r);
if (dl<ans) ask(t[now].l);
}
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%d%d",&t[i].d[0],&t[i].d[1]);
root=build(1,n,0);
for (int i=1;i<=m;i++)
{
int id;
scanf("%d%d%d",&id,&x,&y);
if (id==1)
{
++n;
t[n].mn[0]=t[n].mx[0]=t[n].d[0]=x;
t[n].mn[1]=t[n].mx[1]=t[n].d[1]=y;
insert(n);
}else
{
ans=INF;ask(root);printf("%d\n",ans);
}
}
}
CDQ分治
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define INF 1e9
using namespace std;
const int N=1000005;
struct hh{int x,y,id;}f[N],jl[N],e[N];
int c[N],ans[N],inf;bool flag[N];
void add(int loc,int val)
{
for (int i=loc;i<=inf;i+=i&(-i))
c[i]=max(c[i],val);
}
int qurry(int loc)
{
int ans=0;
for (int i=loc;i>=1;i-=i&(-i)) ans=max(c[i],ans);
return ans==0?-INF:ans;
}
void clear(int loc)
{
for (int i=loc;i<=inf;i+=i&(-i)) c[i]=0;
}
void cdq(int l,int r)
{
if (l>=r) return;
int mid=(l+r)>>1;
cdq(l,mid); cdq(mid+1,r);
int t1=l,t2=mid+1;
for (int i=l;i<=r;i++)
{
if ((t1<=mid && f[t1].x<=f[t2].x)||t2>r)
{
jl[i]=f[t1];
if (!flag[f[t1].id]) add(f[t1].y,f[t1].x+f[t1].y);
t1++;
}else
{
jl[i]=f[t2];
ans[f[t2].id]=min(ans[f[t2].id],f[t2].x+f[t2].y-qurry(f[t2].y));
t2++;
}
}
for (int i=l;i<=mid;i++) if (!flag[f[i].id]) clear(f[i].y);
for (int i=l;i<=r;i++) f[i]=jl[i];
}
int cmp(hh a,hh b){return a.id<b.id;}
int main()
{
int n,m;scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
{
scanf("%d%d",&e[i].x,&e[i].y);
e[i].id=i;
inf=max(inf,e[i].x); inf=max(inf,e[i].y);
}
m+=n;
for (int i=n+1;i<=m;i++)
{
int id;scanf("%d",&id);
if (id==2) flag[i]=1;
scanf("%d%d",&e[i].x,&e[i].y);
e[i].id=i;
inf=max(inf,e[i].x); inf=max(inf,e[i].y);
}
memset(ans,0x7f,sizeof(ans));
for (int i=1;i<=m;i++) f[i]=e[i]; cdq(1,m);
for (int i=1;i<=m;i++) f[i]=e[i],f[i].y=inf-f[i].y+1; cdq(1,m);
for (int i=1;i<=m;i++) f[i]=e[i],f[i].x=inf-f[i].x+1; cdq(1,m);
for (int i=1;i<=m;i++) f[i]=e[i],f[i].x=inf-f[i].x+1,f[i].y=inf-f[i].y+1; cdq(1,m);
for (int i=n+1;i<=m;i++) if (flag[i]) printf("%d\n",ans[i]);
}