Luogu3350 ZJOI2016 旅行者 最短路、分治
生活随笔
收集整理的這篇文章主要介紹了
Luogu3350 ZJOI2016 旅行者 最短路、分治
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
傳送門
題意:給出一個$N \times M$的網格圖,邊有邊權,$Q$組詢問,每組詢問$(x_1,y_1)$到$(x_2,y_2)$的最短路。$N \times M \leq 2 \times 10^4 , Q \leq 10^5$
BZOJ原題竟然沒有數據范圍
矩形的多組詢問問題考慮分治。考慮計算矩形$(x_1,y_1,x_2,y_2)$的詢問,我們將較長邊沿著中線劈成兩半,在這些詢問里面就只可能存在兩種情況:①詢問的兩個端點在中線兩邊,那么路徑就一定會經過中線上一點;②詢問的兩個端點在中線的同一邊,那么有可能不會經過中線,也有可能經過中線。所以我們對中線上所有的點跑一邊整個矩形的最短路,每一次跑完最短路就更新所有的詢問,然后再遞歸進入兩側矩形回答②類型的詢問。時間復雜度似乎是$O(NM \times \sqrt{NM} \times log(NM))$
在$Luogu$題解上學到的一個加速方法:從一個點的最短路轉移到新的點跑最短路的時候,可以不將最短路數組賦值為極大值,而是賦值為這一個點經過上一個計算的點到達所有目標點的答案。
(然而還是在Luogu不開O2的情況下TLE)
1 // luogu-judger-enable-o2 2 //This code is written by Itst 3 #include<bits/stdc++.h> 4 #define pos(i,j) ((i-1)*M+j) 5 using namespace std; 6 7 inline int read(){ 8 int a = 0; 9 bool f = 0; 10 char c = getchar(); 11 while(c != EOF && !isdigit(c)){ 12 if(c == '-') 13 f = 1; 14 c = getchar(); 15 } 16 while(c != EOF && isdigit(c)){ 17 a = (a << 3) + (a << 1) + (c ^ '0'); 18 c = getchar(); 19 } 20 return f ? -a : a; 21 } 22 23 const int MAXN = 100010; 24 int cntEd , N , M , Q , minDis[MAXN] , ans[MAXN] , head[MAXN]; 25 struct Edge{ 26 int end , upEd , w; 27 }Ed[MAXN << 2]; 28 struct query{ 29 int sx , sy , ex , ey , ind; 30 }now[MAXN] , pot[MAXN]; 31 priority_queue < pair < int , int > > q; 32 33 inline void addEd(int a , int b , int c){ 34 Ed[++cntEd].end = b; 35 Ed[cntEd].w = c; 36 Ed[cntEd].upEd = head[a]; 37 head[a] = cntEd; 38 } 39 40 void Dijk(int bx , int by , int lx , int ly , int rx , int ry , int l){ 41 int temp = minDis[pos(bx , by)]; 42 for(int i = lx ; i <= rx ; i++) 43 for(int j = ly ; j <= ry ; j++) 44 minDis[pos(i , j)] = l == 0 ? 0x3f3f3f3f : minDis[pos(i , j)] + temp; 45 minDis[pos(bx , by)] = 0; 46 q.push(make_pair(0 , pos(bx , by))); 47 while(!q.empty()){ 48 pair < int , int > t = q.top(); 49 q.pop(); 50 if(minDis[t.second] != -t.first) 51 continue; 52 for(int i = head[t.second] ; i ; i = Ed[i].upEd) 53 if(minDis[Ed[i].end] > minDis[t.second] + Ed[i].w){ 54 minDis[Ed[i].end] = minDis[t.second] + Ed[i].w; 55 q.push(make_pair(-minDis[Ed[i].end] , Ed[i].end)); 56 } 57 } 58 } 59 60 void solve(int lx , int ly , int rx , int ry , int ql , int qr){ 61 if(ql > qr) 62 return; 63 if(rx - lx > ry - ly){ 64 int mid = lx + rx >> 1; 65 for(int i = ly ; i <= ry ; i++){ 66 Dijk(mid , i , lx , ly , rx , ry , i - ly); 67 for(int j = ql ; j <= qr ; j++) 68 ans[now[j].ind] = min(ans[now[j].ind] , minDis[pos(now[j].sx , now[j].sy)] + minDis[pos(now[j].ex , now[j].ey)]); 69 } 70 int p1 = ql , p2 = qr; 71 for(int i = ql ; i <= qr ; i++) 72 if(now[i].sx < mid && now[i].ex < mid) 73 pot[p1++] = now[i]; 74 else 75 if(now[i].sx > mid && now[i].ex > mid) 76 pot[p2--] = now[i]; 77 memcpy(now + ql , pot + ql , sizeof(query) * (qr - ql + 1)); 78 solve(lx , ly , mid , ry , ql , p1 - 1); 79 solve(mid + 1 , ly , rx , ry , p2 + 1 , qr); 80 } 81 else{ 82 int mid = ly + ry >> 1; 83 for(int i = lx ; i <= rx ; i++){ 84 Dijk(i , mid , lx , ly , rx , ry , i - lx); 85 for(int j = ql ; j <= qr ; j++) 86 ans[now[j].ind] = min(ans[now[j].ind] , minDis[pos(now[j].sx , now[j].sy)] + minDis[pos(now[j].ex , now[j].ey)]); 87 } 88 int p1 = ql , p2 = qr; 89 for(int i = ql ; i <= qr ; i++) 90 if(now[i].sy < mid && now[i].ey < mid) 91 pot[p1++] = now[i]; 92 else 93 if(now[i].sy > mid && now[i].ey > mid) 94 pot[p2--] = now[i]; 95 memcpy(now + ql , pot + ql , sizeof(query) * (qr - ql + 1)); 96 solve(lx , ly , rx , mid , ql , p1 - 1); 97 solve(lx , mid + 1 , rx , ry , p2 + 1 , qr); 98 } 99 } 100 101 int main(){ 102 #ifdef LG 103 freopen("3350.in" , "r" , stdin); 104 freopen("3350.out" , "w" , stdout); 105 #endif 106 memset(ans , 0x3f , sizeof(ans)); 107 N = read(); 108 M = read(); 109 for(int i = 1 ; i <= N ; i++) 110 for(int j = 1 ; j < M ; j++){ 111 int t = read(); 112 addEd(pos(i , j) , pos(i , j + 1) , t); 113 addEd(pos(i , j + 1) , pos(i , j) , t); 114 } 115 for(int i = 1 ; i < N ; i++) 116 for(int j = 1 ; j <= M ; j++){ 117 int t = read(); 118 addEd(pos(i , j) , pos(i + 1 , j) , t); 119 addEd(pos(i + 1 , j) , pos(i , j) , t); 120 } 121 Q = read(); 122 for(int i = 1 ; i <= Q ; i++){ 123 now[i].sx = read(); 124 now[i].sy = read(); 125 now[i].ex = read(); 126 now[i].ey = read(); 127 now[i].ind = i; 128 } 129 solve(1 , 1 , N , M , 1 , Q); 130 for(int i = 1 ; i <= Q ; i++) 131 printf("%d\n" , ans[i]); 132 return 0; 133 }轉載于:https://www.cnblogs.com/Itst/p/9879787.html
總結
以上是生活随笔為你收集整理的Luogu3350 ZJOI2016 旅行者 最短路、分治的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微众银行有信用卡吗?可以申请信用卡吗?
- 下一篇: 广发银行个人网上银行怎么登录?网银登录步