[NOI2019]弹跳(KD-Tree)
被jump送退役了,很生气。
不过切了这题也进不了队,行吧。
退役后写了一下,看到二维平面应该就是KD树,然后可以在KD树上做最短路,然后建立堆和KDTree。然后每次更新则是直接把最短路上的节点删掉,然后合并KDTree
#include<bits/stdc++.h> using namespace std; const int N=1e6+7,M=15e5+7; struct point{int w,l,r,u,d;}p[N]; struct node{int u,d;}; vector<int>G[N]; int n,m,W,H,now,dis,cnt,rt,tot,hd[N],v[M],nxt[M],w[M],vis[N],d[N],ch[N][4]; bool operator<(node x,node y){return x.d>y.d;} priority_queue<node>q; void adde(int x,int y,int z){v[++cnt]=y,nxt[cnt]=hd[x],w[cnt]=z,hd[x]=cnt;} void add(int fa,int&o,int xl,int xr,int yl,int yr,int x,int y) { if(x<xl||x>xr||y<yl||y>yr)return; if(!o)o=++tot; if(o!=rt)adde(fa+n,o+n,0); if(xl==xr&&yl==yr){adde(o+n,now,0);return;} int xm=xl+xr>>1,ym=yl+yr>>1; add(o,ch[o][0],xl,xm,yl,ym,x,y); add(o,ch[o][1],xl,xm,ym+1,yr,x,y); add(o,ch[o][2],xm+1,xr,yl,ym,x,y); add(o,ch[o][3],xm+1,xr,ym+1,yr,x,y); } void link(int o,int xl,int xr,int yl,int yr,int xL,int xR,int yL,int yR) { if(!o||xR<xl||xL>xr||yR<yl||yL>yr||d[o+n]<=dis)return; if(xl>=xL&&xr<=xR&&yl>=yL&&yr<=yR){d[o+n]=dis,q.push((node){o+n,d[o+n]});return;} int xm=xl+xr>>1,ym=yl+yr>>1; link(ch[o][0],xl,xm,yl,ym,xL,xR,yL,yR); link(ch[o][1],xl,xm,ym+1,yr,xL,xR,yL,yR); link(ch[o][2],xm+1,xr,yl,ym,xL,xR,yL,yR); link(ch[o][3],xm+1,xr,ym+1,yr,xL,xR,yL,yR); } int main() { scanf("%d%d%d%d",&n,&m,&W,&H); for(int i=1,x,y;i<=n;i++)scanf("%d%d",&x,&y),now=i,add(0,rt,1,W,1,H,x,y); for(int i=1;i<=m;i++) scanf("%d%d%d%d%d%d",&now,&p[i].w,&p[i].l,&p[i].r,&p[i].u,&p[i].d),G[now].push_back(i); memset(d,63,sizeof d); d[1]=0,q.push((node){1,0}); while(!q.empty()) { int u=q.top().u;q.pop(); if(vis[u])continue; vis[u]=1; for(int i=0,x;i<G[u].size();i++) x=G[u][i],dis=d[u]+p[x].w,link(rt,1,W,1,H,p[x].l,p[x].r,p[x].u,p[x].d); for(int i=hd[u];i;i=nxt[i])if(d[v[i]]>d[u]+w[i])q.push((node){v[i],d[v[i]]=d[u]+w[i]}); } for(int i=2;i<=n;i++)printf("%d\n",d[i]); }