P3350 [ZJOI2016]旅行者

P3350 [ZJOI2016]旅行者

题目描述:

Link

题目分析:

其实就是求 网格图多源多汇最短路 直接做看起来不太可做。

但是。重要的事情说三遍。

网格图先想分治,网格图先想分治,网格图先想分治

类似于整体二分,首先肯定是要把所有的操作都离线下来的。然后我们考虑对于这个网格图,类似于 KDT 的那种建图的分治方式去做。

首先划分这个矩形的时候,肯定要先划分较长的一边,那么此时,我们就相当于在中间画了一条竖线,此时分为两种情况。

  1. 询问不越过这条线,那直接往下进行分治即可
  2. 询问跨过这条线,那么直接枚举中间那条边上的每一个点,更新询问即可。

复杂度貌似是 SSlogS,但是有一个需要注意的点就是枚举边上的每一个点会 T,有一个优化是把最短路的初始值赋为上次最短路的值加上一个起点到这个起点的距离。但是吸氧能过,就这么写了。

复杂度证明

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]); } }
posted @   Zwaire  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 清华大学推出第四讲使用 DeepSeek + DeepResearch 让科研像聊天一样简单!
· 推荐几款开源且免费的 .NET MAUI 组件库
· 实操Deepseek接入个人知识库
· 易语言 —— 开山篇
· Trae初体验
点击右上角即可分享
微信分享提示