4456: [Zjoi2016]旅行者

4456: [Zjoi2016]旅行者

https://www.lydsy.com/JudgeOnline/problem.php?id=4456

分析:

  每次对当前矩阵按长边化一条分治线,然后在对分治线上的点跑最短路,然后可以处理处过分治线的询问。对于不过分治线的,递归处理。

  先写的dijkstra+堆优化,在开O2的情况下可以过,不开O2过不了,卡常~,还是过不了。然后在UOJ的排行榜里(而且UOJ是有大样例的!),看到了两个优化,加上就可以了。

  优化:1、代码41行,用上次的遍历结果初始化。2、将dijkstra改成spfa+SLF优化。

代码:

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<cstring>
  4 #include<cmath>
  5 #include<iostream>
  6 using namespace std;
  7 typedef long long LL;
  8 
  9 char buf[100000],*_p1 = buf,*_p2 = buf;
 10 #define nc() (_p1==_p2&&(_p2=(_p1=buf)+fread(buf,1,100000,stdin),_p1==_p2) ? EOF :*_p1++) 
 11 inline int read() {
 12     int x=0,f=1;char ch=nc();for(;!isdigit(ch);ch=nc())if(ch=='-')f=-1;
 13     for (;isdigit(ch);ch=nc())x=x*10+ch-'0';return x*f;
 14 } 
 15 
 16 #define getid(a,b) ((a - 1) * m + b)
 17 #define pa pair<int,int>
 18 #define mp(a,b) make_pair(a,b)
 19 
 20 const int INF = 1e9;
 21 const int N = 100010;
 22 
 23 struct Que{
 24     int a1,b1,a2,b2,id;
 25 }A[N], B[N];
 26 int dis[N], ans[N], head[N], nxt[N], to[N], len[N];
 27 int n, m, En;
 28 //priority_queue< pa, vector< pa >, greater< pa > > q; // 这才是小根堆!!! 
 29 int q[2000000];
 30 bool vis[N];
 31 
 32 inline void getxy(int id,int &x,int &y) {
 33     x = (id - 1) / m + 1;
 34     y = (id - 1) % m + 1;
 35 }
 36 void dijkstra(int s,int a1,int a2,int b1,int b2,int h) {
 37     int x, y, d = dis[s];
 38     for (int i=a1; i<=a2; ++i) 
 39         for (int j=b1; j<=b2; ++j) {
 40             x = getid(i, j);
 41             dis[x] = h ? dis[x] + d : INF;
 42             vis[x] = false;
 43         }
 44     dis[s] = 0;
 45 /*    q.push(mp(dis[s], s));
 46     while (!q.empty()) {
 47         pa now = q.top(); q.pop();
 48         int u = now.second;
 49         if (vis[u]) continue;
 50         vis[u] = true;
 51         for (int i=head[u]; i; i=nxt[i]) {
 52             int v = to[i];
 53             getxy(v, x, y);
 54             if (x >= a1 && x <= a2 && y >= b1 && y <= b2 && dis[v] > dis[u] + len[i]) {
 55                 dis[v] = dis[u] + len[i];
 56                 q.push(mp(dis[v], v));
 57             }
 58         }
 59     }*/
 60     int L = 100000, R = L - 1;
 61     q[++R] = s;vis[s] = true;
 62     while (L <= R) {
 63         int u = q[L ++];vis[u] = false;
 64         for (int i=head[u]; i; i=nxt[i]) {
 65             int v = to[i];
 66             getxy(v, x, y);
 67             if (x >= a1 && x <= a2 && y >= b1 && y <= b2 && dis[v] > dis[u] + len[i]) {
 68                 dis[v] = dis[u] + len[i];
 69                 if (!vis[v]) {
 70                     if (dis[v] <= dis[q[L]]) q[--L] = v;
 71                     else q[++R] = v;
 72                     vis[v] = true;
 73                 }
 74             }
 75         }
 76     }
 77 }
 78 void solve(int a1,int a2,int b1,int b2,int L,int R) {
 79     if (L > R) return ;
 80     int i, j, k;
 81     if (a2 - a1 > b2 - b1) {
 82         int mid = (a2 + a1) / 2; // a2 + a1
 83         for (i=b1; i<=b2; ++i) {
 84             dijkstra(getid(mid, i), a1, a2, b1, b2, i-b1);
 85             for (j=L; j<=R; ++j) 
 86                 ans[A[j].id] = min(ans[A[j].id], dis[getid(A[j].a1, A[j].b1)] + dis[getid(A[j].a2, A[j].b2)]);
 87         }
 88         i = L - 1, j = R + 1;
 89         for (k=L; k<=R; ++k) {
 90             if (A[k].a1 < mid && A[k].a2 < mid) B[++i] = A[k];
 91             if (A[k].a1 > mid && A[k].a2 > mid) B[--j] = A[k];
 92         }
 93         for (k=L; k<=i; ++k) A[k] = B[k]; solve(a1, mid-1, b1, b2, L, i);
 94         for (k=j; k<=R; ++k) A[k] = B[k]; solve(mid+1, a2, b1, b2, j, R);
 95     }
 96     else {
 97         int mid = (b2 + b1) / 2;
 98         for (i=a1; i<=a2; ++i) {
 99             dijkstra(getid(i, mid), a1, a2, b1, b2, i-a1);
100             for (j=L; j<=R; ++j) 
101                 ans[A[j].id] = min(ans[A[j].id], dis[getid(A[j].a1, A[j].b1)] + dis[getid(A[j].a2, A[j].b2)]);
102         }
103         i = L - 1, j = R + 1;
104         for (k=L; k<=R; ++k) {
105             if (A[k].b1 < mid && A[k].b2 < mid) B[++i] = A[k];
106             if (A[k].b1 > mid && A[k].b2 > mid) B[--j] = A[k];
107         }
108         for (k=L; k<=i; ++k) A[k] = B[k]; solve(a1, a2, b1, mid-1, L, i);
109         for (k=j; k<=R; ++k) A[k] = B[k]; solve(a1, a2, mid+1, b2, j, R);
110     }
111 }
112 inline void add_edge(int u,int v,int w) {
113     ++En; to[En] = v; len[En] = w; nxt[En] = head[u]; head[u] = En;
114     ++En; to[En] = u; len[En] = w; nxt[En] = head[v]; head[v] = En;
115 }
116 int main() {
117     n = read(), m = read();
118     for (int i=1; i<=n; ++i) {
119         for (int j=1; j<m; ++j) {
120             int a = read();
121             add_edge(getid(i, j), getid(i, j + 1), a);
122         }
123     }
124     for (int i=1; i<n; ++i) {
125         for (int j=1; j<=m; ++j) {
126             int a = read();
127             add_edge(getid(i, j), getid(i + 1, j), a);
128         }
129     }
130     int Case = read();
131     for (int a,b,i=1; i<=Case; ++i) {
132         A[i].a1 = read(), A[i].b1 = read(); 
133         A[i].a2 = read(), A[i].b2 = read(); 
134         A[i].id = i; ans[i] = INF;
135     }
136     solve(1, n, 1, m, 1, Case);
137     for (int i=1; i<=Case; ++i) printf("%d\n",ans[i]);
138     return 0;
139 }

 

posted @ 2018-09-08 15:19  MJT12044  阅读(351)  评论(0编辑  收藏  举报