題解 [NOI2019]彈跳
阿新 • • 發佈:2020-10-07
題目大意
給出 \(n\) 做城市,每座城市都有橫縱座標 \(x,y\)。現在給出 \(m\) 個限制 \(p,t,l,r,d,u\),表示從 \(p\) 城市出發,可以花費 \(t\) 走到 \(l\le x\le r,d\le y\le u\) 的一座城市。
問,從城市 1 出發走到每座城市的最小花費是多少?
\(n\le 7\times 10^4,m\le 1.5\times 10^5\)
思路
這道題自己只做出來 \(76\) 分,剩下的感覺還是比較妙吧?
首先不難看出,我們可以用 K-D Tree 優化建圖,大概意思就是 K-D Tree 上的虛點連對應的實點,虛點連兒子,每個點連可以到的點的虛點,然後跑最短路演算法就好了。
這樣做可以看出邊數是 \(m\sqrt n\) 級別的,所以時間複雜度是 \(\Theta(m\sqrt n\log n)\),但是空間複雜度也是 \(m\sqrt n\) 級別的。
我們其實可以考慮不建邊,每次在 K-D Tree 上進行鬆弛操作。這樣空間複雜度就降到了 \(n+m\)。
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define MAXN 140005 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} int n,m,w,h,rt,cut; struct Vector{ int x[2],pos; bool operator < (const Vector &p)const{return x[cut] < p.x[cut];} }city[MAXN],pnt[MAXN]; int mi[MAXN][2],mx[MAXN][2],lson[MAXN],rson[MAXN]; void Mx (int &a,int b){a = max (a,b);} void Mi (int &a,int b){a = min (a,b);} void Pushup (int x){ mi[x][0] = mx[x][0] = city[x].x[0],mi[x][1] = mx[x][1] = city[x].x[1]; if (lson[x]) for (Int i = 0;i < 2;++ i) Mi (mi[x][i],mi[lson[x]][i]),Mx (mx[x][i],mx[lson[x]][i]); if (rson[x]) for (Int i = 0;i < 2;++ i) Mi (mi[x][i],mi[rson[x]][i]),Mx (mx[x][i],mx[rson[x]][i]); } int build (int l,int r,int k){ if (l > r) return 0; int mid = (l + r) >> 1,now = mid;cut = k; nth_element (city + l,city + mid,city + r + 1); if (l == r) return Pushup (now),now; else{ lson[now] = build (l,mid - 1,k ^ 1); rson[now] = build (mid + 1,r,k ^ 1); } Pushup (now); return now; } int dist[MAXN]; bool vis[MAXN]; #define PII pair<int,int> priority_queue <PII,vector <PII>,greater <PII> > q; void Relax (int u,int w){ if (dist[u] > w){ dist[u] = w; if (!vis[u]) q.push (make_pair (dist[u],u)); } } void SolveE (int now,int x1,int x2,int y1,int y2,int ind,int t){ if (!now) return ; if (mi[now][0] > x2 || mx[now][0] < x1 || mi[now][1] > y2 || mx[now][1] < y1) return ; if (mi[now][0] >= x1 && mx[now][0] <= x2 && mi[now][1] >= y1 && mx[now][1] <= y2){ Relax (now,dist[ind] + t); return ; } if (city[now].x[0] >= x1 && city[now].x[0] <= x2 && city[now].x[1] >= y1 && city[now].x[1] <= y2) Relax (city[now].pos,dist[ind] + t); SolveE (lson[now],x1,x2,y1,y2,ind,t); SolveE (rson[now],x1,x2,y1,y2,ind,t); return ; } struct node{int L,R,U,D,T;}; vector <node> G[MAXN]; void Dijkstra (int s){ memset (dist,0x7f,sizeof (dist)); dist[s] = 0,vis[s] = 1; while (!q.empty()) q.pop (); q.push (make_pair (0,s)); while (!q.empty()){ PII now = q.top ();q.pop ();int u = now.second;vis[u] = 1; if (dist[u] != now.first) continue; if (u > n) for (node to : G[u - n]) SolveE (rt,to.L,to.R,to.D,to.U,u,to.T); else Relax (lson[u],dist[u]),Relax (rson[u],dist[u]),Relax (city[u].pos,dist[u]); } } signed main(){ read (n,m,w,h); for (Int i = 1;i <= n;++ i) read (city[i].x[0],city[i].x[1]),city[i].pos = n + i; rt = build (1,n,0);for (Int i = 1;i <= m;++ i){ int p,t,l,r,d,u;read (p,t,l,r,d,u); G[p].push_back (node {l,r,u,d,t}); } Dijkstra (n + 1); for (Int i = 2;i <= n;++ i) write (dist[n + i]),putchar ('\n'); return 0; }