P3350 [ZJOI2016]旅行者
阿新 • • 發佈:2022-04-06
P3350 [ZJOI2016]旅行者
題目描述:
題目分析:
其實就是求 網格圖多源多匯最短路 直接做看起來不太可做。
但是。重要的事情說三遍。
網格圖先想分治,網格圖先想分治,網格圖先想分治
類似於整體二分,首先肯定是要把所有的操作都離線下來的。然後我們考慮對於這個網格圖,類似於 KDT 的那種建圖的分治方式去做。
首先劃分這個矩形的時候,肯定要先劃分較長的一邊,那麼此時,我們就相當於在中間畫了一條豎線,此時分為兩種情況。
- 詢問不越過這條線,那直接往下進行分治即可
- 詢問跨過這條線,那麼直接列舉中間那條邊上的每一個點,更新詢問即可。
複雜度貌似是 \(S\sqrt{S}\log S\)
Code:
//editor : DRYAYST //Wo shi ge da SHA BI //under O2 #include<bits/stdc++.h> #define g() getchar() #define il inline #define ull unsigned long long #define eps 1e-10 #define ll long long #define pa pair<int, int> #define for_1(i, n) for(int i = 1; i <= (n); ++i) #define for_0(i, n) for(int i = 0; i < (n); ++i) #define for_xy(i, x, y) for(int i = (x); i <= (y); ++i) #define for_yx(i, y, x) for(int i = (y); i >= (x); --i) #define for_edge(i, x) for(int i = head[x]; i; i = nxt[i]) #define int long long #define DB double #define ls (p<<1) #define rs (p<<1|1) #define m_p make_pair #define fi first #define se second using namespace std; const int N = 1e6 + 10, INF = 0x7f7f7f7f, mod = 1e9 + 7; il int qpow(int x, int k) {int ans = 1; while(k) {if(k & 1) ans = ans * x % mod; x = x * x % mod; k >>= 1; } return ans; } il int Add(int x, int y) {return (x += y) %= mod;} il int Del(int x, int y) {return (x = x - y + mod) % mod;} il int Mul(int x, int y) {return x * y % mod;} il int inv(int x) {return qpow(x, mod - 2); } il int re() { int x = 0, p = 1; char ch = getchar(); while(ch > '9' || ch < '0') {if(ch == '-') p = -1; ch = getchar();} while(ch <= '9' and ch >= '0') {x = (x << 3) + (x << 1) + (ch ^ 48); ch = getchar();} return x * p; } struct Query{ int x1 , x2, y1 , y2, id;} Q[N], Tp[N]; struct node{ int x, y, w; friend bool operator < (node x , node y){ return x.w > y.w; } }; priority_queue<node> q; int dx[] = {0 , -1 , 0 , 1}, dy[] = {-1 , 0 , 1 , 0}; int ans[N], dis[N], w[N][4], a[N], b[N]; int n, m; il int id(int x , int y) { return (x - 1) * m + y; } il void dij(int l , int r , int x , int y , int x1 , int y1 , int x2 , int y2) { node now = node{x , y , 0}; q.push(now); for(int i = x1; i <= x2; i++) { for(int j = y1; j <= y2; j++) { dis[id(i, j)] = INF; } } dis[id(x , y)] = 0; while(!q.empty()){ now = q.top(), q.pop(); x = now.x, y = now.y; int pos = id(x, y); if(dis[pos] != now.w) continue; for(int i = 0; i < 4; i++) { if(x + dx[i] < x1 || x + dx[i] > x2 || y + dy[i] < y1 || y + dy[i] > y2) continue; int to = id(x + dx[i], y + dy[i]); if(dis[to] > dis[pos] + w[pos][i]){ dis[to] = dis[pos] + w[pos][i]; now = node{x + dx[i] , y + dy[i] , dis[to]}; q.push(now); } } } for(int i = l ; i <= r ; i++){ ans[Q[i].id] = min(ans[Q[i].id] , dis[id(Q[i].x1, Q[i].y1)] + dis[id(Q[i].x2, Q[i].y2)]); } } void solve(int l , int r , int x1 , int x2 , int y1 , int y2){ if(x2 - x1 >= y2 - y1){ int mid = (x1 + x2) >> 1; for(int i = y1; i <= y2; i++) dij(l, r, mid, i, x1, y1, x2, y2); int L = l - 1, R = r + 1; for(int i = l; i <= r; i++) Tp[i] = Q[i]; for(int i = l; i <= r; i++) { if(Tp[i].x1 < mid && Tp[i].x2 < mid) Q[++L] = Tp[i]; if(Tp[i].x1 > mid && Tp[i].x2 > mid) Q[--R] = Tp[i]; } if(l <= L) solve(l, L, x1, mid - 1, y1, y2); if(R <= r) solve(R, r, mid + 1, x2, y1, y2); } else{ int mid = (y1 + y2) >> 1; for(int i = x1; i <= x2; i++) dij(l, r, i, mid, x1, y1, x2, y2); int L = l - 1, R = r + 1; for(int i = l; i <= r; i++) Tp[i] = Q[i]; for(int i = l; i <= r; i++) { if(Tp[i].y1 < mid && Tp[i].y2 < mid) Q[++L] = Tp[i]; if(Tp[i].y1 > mid && Tp[i].y2 > mid) Q[--R] = Tp[i]; } if(l <= L) solve(l, L, x1, x2, y1, mid - 1); if(R <= r) solve(R, r, x1, x2, mid + 1, y2); } } signed main() { n = re(), m = re(); for_1(i, n) for_1(j, m-1) a[id(i,j)] = re(); for_1(i, n-1) for_1(j, m) b[id(i,j)] = re(); for_1(i,n) for_1(j, m) { int x = id(i , j); for(int k = 0; k < 4; k++) { if(i + dx[k] < 1 || i + dx[k] > n || j + dy[k] < 1 || j + dy[k] > m) continue; if(k == 0) w[x][k] = a[id(i , j - 1)]; if(k == 1) w[x][k] = b[id(i - 1 , j)]; if(k == 2) w[x][k] = a[id(i , j)]; if(k == 3) w[x][k] = b[id(i , j)]; } } int qnum = re(); for(int i = 1; i <= qnum; i++) { Q[i].x1 = re(), Q[i].y1 = re(), Q[i].x2 = re(), Q[i].y2 = re(); Q[i].id = i; } memset(ans, 0x3f, sizeof(ans)); solve(1, qnum, 1, n, 1, m); for_1(i, qnum) {printf("%lld\n", ans[i]); } }