本题可以用的方法很多,除去以下三种我所知道的就还有至少三种。

方法一:类似线段树优化建图,将一个平面等分成四份(若只有一行或一列则等分成两份),然后跑Dijkstra即可。建树是$O(n\log n)$的,单次连边是$O(n\log^2 n)$的。

 1 #include<queue>
 2 #include<vector>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<algorithm>
 6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
 7 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
 8 using namespace std;
 9 
10 const int N=1000010,M=1500010;
11 struct E{ int w,l,r,u,d; }p[N];
12 struct P{ int u,d; };
13 vector<int>G[N];
14 int n,m,W,H,now,dis,x,y,cnt,rt,tot,h[N],to[M],nxt[M],w[M],vis[N],d[N],ch[N][4];
15 bool operator <(P x,P y){ return x.d>y.d; }
16 priority_queue<P>Q;
17 void add(int x,int y,int z){ to[++cnt]=y; nxt[cnt]=h[x]; w[cnt]=z; h[x]=cnt; }
18 
19 void ins(int fa,int &k,int xl,int xr,int yl,int yr,int x,int y){
20     if (x<xl||x>xr||y<yl||y>yr) return;
21     if (!k) k=++tot;
22     if (k!=rt) add(fa+n,k+n,0);
23     if (xl==xr&&yl==yr){ add(k+n,now,0); return; }
24     int xm=(xl+xr)>>1,ym=(yl+yr)>>1;
25     ins(k,ch[k][0],xl,xm,yl,ym,x,y);
26     ins(k,ch[k][1],xl,xm,ym+1,yr,x,y);
27     ins(k,ch[k][2],xm+1,xr,yl,ym,x,y);
28     ins(k,ch[k][3],xm+1,xr,ym+1,yr,x,y);
29 }
30 
31 void link(int k,int xl,int xr,int yl,int yr,int xL,int xR,int yL,int yR){
32     if (!k||xR<xl||xL>xr||yR<yl||yL>yr||d[k+n]<=dis) return;
33     if (xl>=xL&&xr<=xR&&yl>=yL&&yr<=yR){ d[k+n]=dis; Q.push((P){k+n,d[k+n]}); return; }
34     int xm=(xl+xr)>>1,ym=(yl+yr)>>1;
35     link(ch[k][0],xl,xm,yl,ym,xL,xR,yL,yR);
36     link(ch[k][1],xl,xm,ym+1,yr,xL,xR,yL,yR);
37     link(ch[k][2],xm+1,xr,yl,ym,xL,xR,yL,yR);
38     link(ch[k][3],xm+1,xr,ym+1,yr,xL,xR,yL,yR);
39 }
40 
41 int main(){
42     freopen("jump.in","r",stdin);
43     freopen("jump.out","w",stdout);
44     scanf("%d%d%d%d",&n,&m,&W,&H);
45     rep(i,1,n) scanf("%d%d",&x,&y),now=i,ins(0,rt,1,W,1,H,x,y);
46     rep(i,1,m) 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);
47     memset(d,63,sizeof(d)); d[1]=0; Q.push((P){1,0});
48     while (!Q.empty()){
49         int u=Q.top().u; Q.pop();
50         if (vis[u]) continue; vis[u]=1;
51         for (int i=0;i<(int)G[u].size();i++)
52             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);
53         For(i,u) if (d[k=to[i]]>d[u]+w[i]) Q.push((P){k,d[k]=d[u]+w[i]});
54     }
55     rep(i,2,n) printf("%d\n",d[i]);
56     return 0;
57 }
四分树

相关文章: