diff --git a/CF1681.md b/CF1681.md new file mode 100644 index 0000000..11cc19e --- /dev/null +++ b/CF1681.md @@ -0,0 +1,101 @@ +# CF1681E Labyrinth Adventures + +## 题目描述 + +有一个 $n\times n$ 的方格图,坐标编号类似平面直角坐标系,左下角为 $(1, 1)$。 + +这个方格图被分成了 $n$ 层,左下角 $(1, 1)$ 为第一层,随后每层都向外拓展一圈,如下图就是 $n=5$ 的时候的情况: + +![](https://espresso.codeforces.com/003bbba1ff0347bde56714b878262c5fe414679d.png) + +层与层之间有墙隔开,但每层都有两个门,分别分布在该层顶部和右侧,门是双向的。 + +现在给出这些门的坐标,有 $m$ 次询问,每次给定两个坐标 $(x_1, y_1)$ 和 $(x_2,y_2)$,请你回答两点之间的最短路。 + +## 输入格式 + +第一行输入 $n$。 + +接下来的 $n-1$ 行中,每行有四个整数 $d_{1,x}, d_{1,y}, d_{2,x}, d_{2,y}$,表示第 $i$ 层的两个门的坐标。前两个表示顶部门坐标,后两个表示右侧门坐标。 + +之后一行输入 $m$。 + +接下来的 $m$ 行中,每行有四个整数 $x_1,y_1,x_2,y_2$,表示每次询问中起点与终点的坐标。 + +## 输出格式 + +对每次询问,输出一行一个整数,表示两点之间的最短路长度。**长度的定义是移动的步数。** + +## 输入输出样例 #1 + +### 输入 #1 + +``` +2 +1 1 1 1 +10 +1 1 1 1 +1 1 1 2 +1 1 2 1 +1 1 2 2 +1 2 1 2 +1 2 2 1 +1 2 2 2 +2 1 2 1 +2 1 2 2 +2 2 2 2 +``` + +### 输出 #1 + +``` +0 +1 +1 +2 +0 +2 +1 +0 +1 +0 +``` + +## 输入输出样例 #2 + +### 输入 #2 + +``` +4 +1 1 1 1 +2 1 2 2 +3 2 1 3 +5 +2 4 4 3 +4 4 3 3 +1 2 3 3 +2 2 4 4 +1 4 2 3 +``` + +### 输出 #2 + +``` +3 +4 +3 +6 +2 +``` + +## 说明/提示 + +#### 样例解释 + +下图是样例二的网格图,红色的是门。 + +![](https://espresso.codeforces.com/522ad0e61c0b740a60c9203c9178279992c8ab2e.png) +#### 数据范围 +$1 \le n \le 10^5$; + +$2 \le m \le 2 \times 10^5$。 \ No newline at end of file diff --git a/CF1681E.cpp b/CF1681E.cpp new file mode 100644 index 0000000..4e9d6a2 --- /dev/null +++ b/CF1681E.cpp @@ -0,0 +1,84 @@ +#include +#define int long long +using namespace std; +typedef pair pii; +const int INF = 1e18; +int n; +pair doors[100005]; +int m; +int dp[100005][20][2][2]; +signed main() +{ + scanf("%lld", &n); + for (int i = 1; i < n; ++i) + { + int xx1, yy1, xx2, yy2; + scanf("%lld%lld%lld%lld", &xx1, &yy1, &xx2, &yy2); + doors[i] = {{xx1, yy1}, {xx2, yy2}}; + } + for(int i = 2; i < n; ++i) { + for (int a = 0; a < 2; ++a) { + pii out; + if (a == 0) out = {doors[i - 1].first.first + 1, doors[i - 1].first.second}; + else out = {doors[i - 1].second.first, doors[i - 1].second.second + 1}; + for (int b = 0; b < 2; ++b) { + pii dest = (b == 0) ? doors[i].first : doors[i].second; + dp[i - 1][0][a][b] = 1 + abs(out.first - dest.first) + abs(out.second - dest.second); + } + } + } + for(int i = 1; i <= 19; ++i) { + for(int j = 1; j + (1 << i) <= n - 1; ++j) { + dp[j][i][0][0] = min(dp[j][i - 1][0][0] + dp[j + (1 << (i - 1))][i - 1][0][0], dp[j][i - 1][0][1] + dp[j + (1 << (i - 1))][i - 1][1][0]); + dp[j][i][0][1] = min(dp[j][i - 1][0][0] + dp[j + (1 << (i - 1))][i - 1][0][1], dp[j][i - 1][0][1] + dp[j + (1 << (i - 1))][i - 1][1][1]); + dp[j][i][1][0] = min(dp[j][i - 1][1][0] + dp[j + (1 << (i - 1))][i - 1][0][0], dp[j][i - 1][1][1] + dp[j + (1 << (i - 1))][i - 1][1][0]); + dp[j][i][1][1] = min(dp[j][i - 1][1][0] + dp[j + (1 << (i - 1))][i - 1][0][1], dp[j][i - 1][1][1] + dp[j + (1 << (i - 1))][i - 1][1][1]); + } + } + scanf("%lld", &m); + while (m--) + { + pii s, e; + scanf("%lld%lld%lld%lld", &s.first, &s.second, &e.first, &e.second); + int sc = max(s.first, s.second); + int ec = max(e.first, e.second); + if(sc > ec) swap(sc, ec), swap(s, e); + else if(sc == ec) { + printf("%lld\n", abs(s.first - e.first) + abs(s.second - e.second)); + continue; + } + ec--; + int ds[2], de[2]; + ds[0] = abs(doors[sc].first.first - s.first) + abs(doors[sc].first.second - s.second); + ds[1] = abs(doors[sc].second.first - s.first) + abs(doors[sc].second.second - s.second); + for (int b = 0; b < 2; ++b) { + pii out; + if (b == 0) out = {doors[ec].first.first + 1, doors[ec].first.second}; + else out = {doors[ec].second.first, doors[ec].second.second + 1}; + de[b] = 1 + abs(out.first - e.first) + abs(out.second - e.second); + } + int M[2][2] = {{0, INF}, {INF, 0}}; + int now = sc; + int len = ec - sc; + for (int i = 19; i >= 0; --i) { + if (len >= (1 << i)) { + int tmp[2][2]; + for (int a = 0; a < 2; ++a) + for (int b = 0; b < 2; ++b) { + tmp[a][b] = INF; + for (int k = 0; k < 2; ++k) + tmp[a][b] = min(tmp[a][b], M[a][k] + dp[now][i][k][b]); + } + memcpy(M, tmp, sizeof(M)); + now += (1 << i); + len -= (1 << i); + } + } + int ans = INF; + for (int a = 0; a < 2; ++a) + for (int b = 0; b < 2; ++b) + ans = min(ans, ds[a] + M[a][b] + de[b]); + printf("%lld\n", ans); + } + return 0; +} \ No newline at end of file