KD树的空间复杂度是O(n)O(n)的 「NOI2019」弹跳 题解(KD树)

「NOI2019」弹跳 题解(KD树)

 

题意:w×h网格中有n个点,m条边。每条边可以从p点花费t时间到一个矩形中的任意点,求1号点到每个点的最少时间。
1<=w,h<=n<=700001<=m<=1500001<=w,h<=n<=70000,1<=m<=150000
时间2s,空间128M

本题如果放在序列上,使用线段树建图,可以做到O(mlogn)O(mlogn)的复杂度,通过数据分治可以获得72分。
对于二维问题可以想到将线段树变为二维线段树,然而会被卡空间。
考虑此题暴力Dij的本质:就是每次找最小的点,然后把一个矩形中大于z的数都改为z,再删除这个点。
看到矩形修改,可以想到KD树。
KD树的空间复杂度是O(n)O(n)的,很优秀。
在矩形修改时,采用类似线段树的方法:如果当前矩形与修改的矩形没有交,就直接返回。如果被包含,则直接打标记。
但与线段树不同的:还需要考虑当前的点是否在矩形内,如果在则直接修改这个点。
这就是KD树处理矩形的方法。
时间复杂度:O(mn−−√)O(mn)。
删除一个点可以打一个特殊标记实现。
把这个写上后,会发现超时。
考虑剪枝:如果z大于当前点的标记,就直接返回。
这样就能过了。

代码:

#include <stdio.h>
#include <stdlib.h> #define max(a,b) a>b?a:b #define min(a,b) a<b?a:b struct SPx { int x,y,i; SPx(){} SPx(int X,int Y,int I) { x=X;y=Y;i=I; } }; int cmpx(const void*a,const void*b) { return ((SPx*)a)->x-((SPx*)b)->x; } int cmpy(const void*a,const void*b) { return ((SPx*)a)->y-((SPx*)b)->y; } int cl[70010],cr[70010],fa[70010],lx[70010],rx[70010],ly[70010],ry[70010]; int zx[70010],wz[70010],qz[70010],ld[70010],inf=2000000000,root; bool bk[70010]; void update(int x) { if(bk[x]) zx[x]=inf,wz[x]=-1; else zx[x]=qz[x],wz[x]=x; if(cl[x]!=0&&wz[cl[x]]!=-1&&zx[cl[x]]<=zx[x]) zx[x]=zx[cl[x]],wz[x]=wz[cl[x]]; if(cr[x]!=0&&wz[cr[x]]!=-1&&zx[cr[x]]<=zx[x]) zx[x]=zx[cr[x]],wz[x]=wz[cr[x]]; } void pur(int x,int y) { if(ld[x]!=-1&&y>=ld[x]) return; ld[x]=y; if(qz[x]>y)qz[x]=y; if(zx[x]>y)zx[x]=y; } void pushdown(int x) { if(ld[x]==-1)return; if(cl[x]!=0)pur(cl[x],ld[x]); if(cr[x]!=0)pur(cr[x],ld[x]); ld[x]=-1; } void clean(int x) { if(fa[x]!=0) clean(fa[x]); pushdown(x); } void del(int x) { clean(x); bk[x]=true; for(int i=x;i!=0;i=fa[i]) update(i); } int buix(SPx sz[70010],int l,int r); int buiy(SPx sz[70010],int l,int r); void pushup(int rt) { if(cl[rt]!=0) { lx[rt]=min(lx[rt],lx[cl[rt]]);rx[rt]=max(rx[rt],rx[cl[rt]]); ly[rt]=min(ly[rt],ly[cl[rt]]);ry[rt]=max(ry[rt],ry[cl[rt]]); fa[cl[rt]]=rt; } if(cr[rt]!=0) { lx[rt]=min(lx[rt],lx[cr[rt]]);rx[rt]=max(rx[rt],rx[cr[rt]]); ly[rt]=min(ly[rt],ly[cr[rt]]);ry[rt]=max(ry[rt],ry[cr[rt]]); fa[cr[rt]]=rt; } } bool fugai(int Lx,int Rx,int Ly,int Ry,int lx,int rx,int ly,int ry) { return Lx<=lx&&rx<=Rx&&Ly<=ly&&ry<=Ry; } bool fenli(int Lx,int Rx,int Ly,int Ry,int lx,int rx,int ly,int ry) { return Lx>rx||lx>Rx||Ly>ry||ly>Ry; } int X[70010],Y[70010]; int buix(SPx sz[70010],int l,int r) { if(l>=r)return 0; qsort(sz+l,r-l,sizeof(SPx),cmpx); int m=(l+r-1)>>1,rt=sz[m].i; lx[rt]=rx[rt]=sz[m].x; ly[rt]=ry[rt]=sz[m].y; cl[rt]=buiy(sz,l,m); cr[rt]=buiy(sz,m+1,r); pushup(rt); return rt; } int buiy(SPx sz[70010],int l,int r) { if(l>=r)return 0; qsort(sz+l,r-l,sizeof(SPx),cmpy); int m=(l+r-1)>>1,rt=sz[m].i; lx[rt]=rx[rt]=sz[m].x; ly[rt]=ry[rt]=sz[m].y; cl[rt]=buix(sz,l,m); cr[rt]=buix(sz,m+1,r); pushup(rt); return rt; } void songc(int i,int Lx,int Rx,int Ly,int Ry,int z) { if(ld[i]!=-1&&z>ld[i]) return; if(fenli(Lx,Rx,Ly,Ry,lx[i],rx[i],ly[i],ry[i])) return; if(fugai(Lx,Rx,Ly,Ry,lx[i],rx[i],ly[i],ry[i])) { pur(i,z); return; } pushdown(i); if(fugai(Lx,Rx,Ly,Ry,X[i],X[i],Y[i],Y[i])) { if(qz[i]>z) qz[i]=z; update(i); } if(cl[i]!=0) songc(cl[i],Lx,Rx,Ly,Ry,z); if(cr[i]!=0) songc(cr[i],Lx,Rx,Ly,Ry,z); update(i); } void dfs(int u) { if(cl[u]!=0) dfs(cl[u]); if(cr[u]!=0) dfs(cr[u]); update(u); } int dis[70010]; int fr[70010],ne[150010],x1[150010],x2[150010],y1[150010],y2[150010],w[150010],bs=0; void addb(int a,int lx,int rx,int ly,int ry,int b) { x1[bs]=lx;x2[bs]=rx; y1[bs]=ly;y2[bs]=ry; w[bs]=b; ne[bs]=fr[a]; fr[a]=bs++; } SPx sz[70010]; void dij(int u,int n) { for(int i=1;i<=n;i++) sz[i]=SPx(X[i],Y[i],i); root=buix(sz,1,n+1); for(int i=1;i<=n;i++) qz[i]=inf; qz[u]=0; dfs(root); while(1) { int t=wz[root],x=zx[root]; if(t==-1)break; del(t);dis[t]=x; for(int i=fr[t];i!=-1;i=ne[i]) songc(root,x1[i],x2[i],y1[i],y2[i],x+w[i]); } } int main() { wz[0]=-1; int n,m,w,h; scanf("%d%d%d%d",&n,&m,&w,&h); for(int i=1;i<=n;i++) scanf("%d%d",&X[i],&Y[i]); for(int i=1;i<=n;i++) fr[i]=ld[i]=-1; for(int i=0;i<m;i++) { int p,t,l,r,d,u; scanf("%d%d%d%d%d%d",&p,&t,&l,&r,&d,&u); addb(p,l,r,d,u,t); } dij(1,n); for(int i=2;i<=n;i++) printf("%d\n",dis[i]); return 0; }
 
分类:  题解

题意:w×h网格中有n个点,m条边。每条边可以从p点花费t时间到一个矩形中的任意点,求1号点到每个点的最少时间。
1<=w,h<=n<=700001<=m<=1500001<=w,h<=n<=70000,1<=m<=150000
时间2s,空间128M

本题如果放在序列上,使用线段树建图,可以做到O(mlogn)O(mlogn)的复杂度,通过数据分治可以获得72分。
对于二维问题可以想到将线段树变为二维线段树,然而会被卡空间。
考虑此题暴力Dij的本质:就是每次找最小的点,然后把一个矩形中大于z的数都改为z,再删除这个点。
看到矩形修改,可以想到KD树。
KD树的空间复杂度是O(n)O(n)的,很优秀。
在矩形修改时,采用类似线段树的方法:如果当前矩形与修改的矩形没有交,就直接返回。如果被包含,则直接打标记。
但与线段树不同的:还需要考虑当前的点是否在矩形内,如果在则直接修改这个点。
这就是KD树处理矩形的方法。
时间复杂度:O(mn−−√)O(mn)。
删除一个点可以打一个特殊标记实现。
把这个写上后,会发现超时。
考虑剪枝:如果z大于当前点的标记,就直接返回。
这样就能过了。

代码:

#include <stdio.h>
#include <stdlib.h> #define max(a,b) a>b?a:b #define min(a,b) a<b?a:b struct SPx { int x,y,i; SPx(){} SPx(int X,int Y,int I) { x=X;y=Y;i=I; } }; int cmpx(const void*a,const void*b) { return ((SPx*)a)->x-((SPx*)b)->x; } int cmpy(const void*a,const void*b) { return ((SPx*)a)->y-((SPx*)b)->y; } int cl[70010],cr[70010],fa[70010],lx[70010],rx[70010],ly[70010],ry[70010]; int zx[70010],wz[70010],qz[70010],ld[70010],inf=2000000000,root; bool bk[70010]; void update(int x) { if(bk[x]) zx[x]=inf,wz[x]=-1; else zx[x]=qz[x],wz[x]=x; if(cl[x]!=0&&wz[cl[x]]!=-1&&zx[cl[x]]<=zx[x]) zx[x]=zx[cl[x]],wz[x]=wz[cl[x]]; if(cr[x]!=0&&wz[cr[x]]!=-1&&zx[cr[x]]<=zx[x]) zx[x]=zx[cr[x]],wz[x]=wz[cr[x]]; } void pur(int x,int y) { if(ld[x]!=-1&&y>=ld[x]) return; ld[x]=y; if(qz[x]>y)qz[x]=y; if(zx[x]>y)zx[x]=y; } void pushdown(int x) { if(ld[x]==-1)return; if(cl[x]!=0)pur(cl[x],ld[x]); if(cr[x]!=0)pur(cr[x],ld[x]); ld[x]=-1; } void clean(int x) { if(fa[x]!=0) clean(fa[x]); pushdown(x); } void del(int x) { clean(x); bk[x]=true; for(int i=x;i!=0;i=fa[i]) update(i); } int buix(SPx sz[70010],int l,int r); int buiy(SPx sz[70010],int l,int r); void pushup(int rt) { if(cl[rt]!=0) { lx[rt]=min(lx[rt],lx[cl[rt]]);rx[rt]=max(rx[rt],rx[cl[rt]]); ly[rt]=min(ly[rt],ly[cl[rt]]);ry[rt]=max(ry[rt],ry[cl[rt]]); fa[cl[rt]]=rt; } if(cr[rt]!=0) { lx[rt]=min(lx[rt],lx[cr[rt]]);rx[rt]=max(rx[rt],rx[cr[rt]]); ly[rt]=min(ly[rt],ly[cr[rt]]);ry[rt]=max(ry[rt],ry[cr[rt]]); fa[cr[rt]]=rt; } } bool fugai(int Lx,int Rx,int Ly,int Ry,int lx,int rx,int ly,int ry) { return Lx<=lx&&rx<=Rx&&Ly<=ly&&ry<=Ry; } bool fenli(int Lx,int Rx,int Ly,int Ry,int lx,int rx,int ly,int ry) { return Lx>rx||lx>Rx||Ly>ry||ly>Ry; } int X[70010],Y[70010]; int buix(SPx sz[70010],int l,int r) { if(l>=r)return 0; qsort(sz+l,r-l,sizeof(SPx),cmpx); int m=(l+r-1)>>1,rt=sz[m].i; lx[rt]=rx[rt]=sz[m].x; ly[rt]=ry[rt]=sz[m].y; cl[rt]=buiy(sz,l,m); cr[rt]=buiy(sz,m+1,r); pushup(rt); return rt; } int buiy(SPx sz[70010],int l,int r) { if(l>=r)return 0; qsort(sz+l,r-l,sizeof(SPx),cmpy); int m=(l+r-1)>>1,rt=sz[m].i; lx[rt]=rx[rt]=sz[m].x; ly[rt]=ry[rt]=sz[m].y; cl[rt]=buix(sz,l,m); cr[rt]=buix(sz,m+1,r); pushup(rt); return rt; } void songc(int i,int Lx,int Rx,int Ly,int Ry,int z) { if(ld[i]!=-1&&z>ld[i]) return; if(fenli(Lx,Rx,Ly,Ry,lx[i],rx[i],ly[i],ry[i])) return; if(fugai(Lx,Rx,Ly,Ry,lx[i],rx[i],ly[i],ry[i])) { pur(i,z); return; } pushdown(i); if(fugai(Lx,Rx,Ly,Ry,X[i],X[i],Y[i],Y[i])) { if(qz[i]>z) qz[i]=z; update(i); } if(cl[i]!=0) songc(cl[i],Lx,Rx,Ly,Ry,z); if(cr[i]!=0) songc(cr[i],Lx,Rx,Ly,Ry,z); update(i); } void dfs(int u) { if(cl[u]!=0) dfs(cl[u]); if(cr[u]!=0) dfs(cr[u]); update(u); } int dis[70010]; int fr[70010],ne[150010],x1[150010],x2[150010],y1[150010],y2[150010],w[150010],bs=0; void addb(int a,int lx,int rx,int ly,int ry,int b) { x1[bs]=lx;x2[bs]=rx; y1[bs]=ly;y2[bs]=ry; w[bs]=b; ne[bs]=fr[a]; fr[a]=bs++; } SPx sz[70010]; void dij(int u,int n) { for(int i=1;i<=n;i++) sz[i]=SPx(X[i],Y[i],i); root=buix(sz,1,n+1); for(int i=1;i<=n;i++) qz[i]=inf; qz[u]=0; dfs(root); while(1) { int t=wz[root],x=zx[root]; if(t==-1)break; del(t);dis[t]=x; for(int i=fr[t];i!=-1;i=ne[i]) songc(root,x1[i],x2[i],y1[i],y2[i],x+w[i]); } } int main() { wz[0]=-1; int n,m,w,h; scanf("%d%d%d%d",&n,&m,&w,&h); for(int i=1;i<=n;i++) scanf("%d%d",&X[i],&Y[i]); for(int i=1;i<=n;i++) fr[i]=ld[i]=-1; for(int i=0;i<m;i++) { int p,t,l,r,d,u; scanf("%d%d%d%d%d%d",&p,&t,&l,&r,&d,&u); addb(p,l,r,d,u,t); } dij(1,n); for(int i=2;i<=n;i++) printf("%d\n",dis[i]); return 0; }

猜你喜欢

转载自www.cnblogs.com/strugksjncxa/p/11256063.html