QGRID code

给定一个 n × m(1 <= m <= 3) 的点网格,网格的边上以及点上都有权值。
初始时所有点的权值都为 0 。
维护两种操作:
1. x1 y1 x2 y2 c 把从 (x1, y1) 到 (x2, y2) 的最短路上的所有节点的权值都增加 c 。保证最短路唯一。
2. x y 询问 (x, y) 的权值。

解:

为了方便,所有编号均从 0 开始。

对于操作1,我们不妨设 x1 <= x2 。
我们先考虑 (x1, y1) 和 (x2, y2) 之间的最短路可以由哪些简单的部分构成:
1. 允许经过整个网格,(x1, y1) 经过最短路走到 (x1, p)。
2. 仅允许经过 [x1, x2] × [0, m-1] ,(x1, p) 经过最短路走到 (x2, q)。
3. 允许经过整个网格,(x2, q) 经过最短路走到 (x2, y2)。
其中 0 <= p, q < m 。

允许经过整个网络,(x, y) 走到 (x, y') 的最短路由以下几个部分构成:
1. 仅允许经过 [0, x] × [0, m-1] ,(x, y) 经过最短路走到 (x, p)。
2. 仅允许经过 [x, n-1] × [0, m-1] ,(x, p) 经过最短路走到 (x, y')。
或者
1'. 仅允许经过 [x, n-1] × [0, m-1] ,(x, y) 经过最短路走到 (x, p)。
2'. 仅允许经过 [0, x] × [0, m-1] ,(x, p) 经过最短路走到 (x, y')。
其中 0 <= p < m 。

综合以上,我们可以把 (x1, y1) 和 (x2, y2) 之间的最短路 用至多 5 个如下特殊的最短路连接起来:
仅允许经过 [L, R] × [0, m-1] ,(p) 走到 (q) 的最短路。
其中,对于确定的区间[L, R],我们把 点(L, p) 简记为 (p),把 点(R, q) 简记为 (q+m)。
其中,0 <= p, q < 2*m。

这样的最短路可以考虑用线段树去维护。

考虑区间[L, R]所维护的信息:
仅经过 [L, R] × [0, m-1] 之内的点,(p) 走到 (q) 的最短路长度 dis[p][q]。

假设两个区间分别是 [L, mid] 和 [mid+1, R] ,如何合并两个区间的答案见如下代码:

 1 void get(int k, int L, int R, int x, int y, node *res)
 2 {
 3     if (L == x && R == y)
 4     {
 5         memcpy(&res[k], &tree[k], sizeof(node));
 6         return;
 7     }
 8     int mid = (L+R)/2;
 9     if (y <= mid)
10     {
11         get(k<<1, L, mid, x, y, res);
12         memcpy(&res[k], &res[k<<1], sizeof(node));
13     }
14     else if (x > mid)
15     {
16         get(k<<1|1, mid+1, R, x, y, res);
17         memcpy(&res[k], &res[k<<1|1], sizeof(node));
18     }
19     else
20     {
21         get(k<<1, L, mid, x, mid, res);
22         get(k<<1|1, mid+1, R, mid+1, y, res);
23         for (int i = 0; i < m; ++ i)
24             for (int j = i+1; j < m; ++ j)
25             {
26                 res[k].dis[i][j] = res[k<<1].dis[i][j];
27                 res[k].dis[i+m][j+m] = res[k<<1|1].dis[i+m][j+m];
28                 for (int p = 0; p < m; ++ p)
29                     for (int q = 0; q < m; ++ q) if (p != q)
30                     {
31                         res[k].dis[i][j] = min(res[k].dis[i][j], res[k<<1].dis[i][p+m]+res[k<<1|1].dis[p][q]+res[k<<1].dis[j][q+m]+rc[mid][p]+rc[mid][q]);
32                         res[k].dis[i+m][j+m] = min(res[k].dis[i+m][j+m], res[k<<1|1].dis[p][i+m]+res[k<<1].dis[p+m][q+m]+res[k<<1|1].dis[q][j+m]+rc[mid][p]+rc[mid][q]);
33                     }
34                 res[k].dis[j][i] = res[k].dis[i][j];
35                 res[k].dis[j+m][i+m] = res[k].dis[i+m][j+m];
36             }
37         for (int i = 0; i < m; ++ i)
38             for (int j = 0; j < m; ++ j)
39             {
40                 res[k].dis[i][j+m] = INF;
41                 for (int p = 0; p < m; ++ p)
42                     res[k].dis[i][j+m] = min(res[k].dis[i][j+m], res[k<<1].dis[i][p+m]+res[k<<1|1].dis[p][j+m]+rc[mid][p]);
43                 if (m == 3)
44                 {
45                     for (int p = 0; p < m; ++ p)
46                         for (int q = 0; q < m; ++ q) if (p != q)
47                             res[k].dis[i][j+m] = min(res[k].dis[i][j+m], res[k<<1].dis[i][p+m]+res[k<<1|1].dis[p][q]+res[k<<1].dis[q+m][(3-p-q)+m]+res[k<<1|1].dis[(3-p-q)][j+m]+rc[mid][0]+rc[mid][1]+rc[mid][2]);
48                 }
49                 res[k].dis[j+m][i] = res[k].dis[i][j+m];
50             }
51     }
52 }
get

相关文章:

  • 2021-12-02
  • 2022-01-15
  • 2021-09-30
  • 2022-02-11
  • 2022-12-23
  • 2021-09-17
  • 2021-09-27
  • 2021-10-05
猜你喜欢
  • 2021-10-11
  • 2021-11-01
  • 2021-11-01
  • 2021-10-16
  • 2021-08-20
  • 2021-08-03
  • 2021-10-25
相关资源
相似解决方案