1. 程式人生 > 其它 >P3350 [ZJOI2016]旅行者

P3350 [ZJOI2016]旅行者

P3350 [ZJOI2016]旅行者

題目描述:

Link

題目分析:

其實就是求 網格圖多源多匯最短路 直接做看起來不太可做。

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

網格圖先想分治,網格圖先想分治,網格圖先想分治

類似於整體二分,首先肯定是要把所有的操作都離線下來的。然後我們考慮對於這個網格圖,類似於 KDT 的那種建圖的分治方式去做。

首先劃分這個矩形的時候,肯定要先劃分較長的一邊,那麼此時,我們就相當於在中間畫了一條豎線,此時分為兩種情況。

  1. 詢問不越過這條線,那直接往下進行分治即可
  2. 詢問跨過這條線,那麼直接列舉中間那條邊上的每一個點,更新詢問即可。

複雜度貌似是 \(S\sqrt{S}\log S\)

,但是有一個需要注意的點就是列舉邊上的每一個點會 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]); }
}