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 }