题目大意 :
有一个由 "_", “|”, “ ”构成的图,任意两个格子之间的路径是唯一的, 现在有Q个点, 编号分别为1 到 Q, 输出从1 - > 2 + 2 - > 3…… 到 Q的路径之和, 不可以跳过
思路 :
建图见代码备注, 建完图后就是LCA裸题, 注意开long long, 否则1000 * 1000 * 10000 会炸int
Accepted code
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 1e6 + 100;
const int MAXM = 2e3 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }
vector <ll> e[MAXN << 1];
string mp[MAXM];
ll dep[MAXN], c[MAXN], n, m, q;
ll dis[MAXN], p[MAXN][25];
ll dir[4][2] = { -1, 0, 1, 0, 0, 2, 0, -2 }; // 4个方向
bool vis[MAXN];
ll id(ll x, ll y) {
return (x - 1) * m + y / 2; // 点的编号
}
bool check(ll x, ll y) { // 不能跑出图
if (x < 1 || x > n || y < 2 || y > 2 * m) return false;
return true;
}
void add(ll x, ll y) {
ll ui = id(x, y);
for (ll i = 0; i < 4; i++) {
ll xx = x + dir[i][0];
ll yy = y + dir[i][1];
if (!check(xx, y)) continue;
ll vi = id(xx, yy);
if (!i && mp[xx][yy] == ' ') e[ui].push_back(vi); // 往上
else if (i == 1 && mp[x][y] == ' ') e[ui].push_back(vi); // 往下
else if (i == 2 && mp[xx][yy - 1] != '|') e[ui].push_back(vi); // 往左
else if (i == 3 && mp[xx][yy + 1] != '|') e[ui].push_back(vi); // 往右
}
}
void dfs(ll x, ll fa) {
vis[x] = true;
dep[x] = dep[fa] + 1; p[x][0] = fa;
for (ll i = 1; (1 << i) <= dep[x]; i++)
p[x][i] = p[p[x][i - 1]][i - 1];
for (auto it : e[x]) {
ll vi = it;
if (vi == fa || vis[vi]) continue;
dis[vi] = dis[x] + 1; dfs(vi, x);
}
}
ll LCA(ll x, ll y) {
if (dep[x] > dep[y]) swap(x, y);
for (ll i = 20; i >= 0; i--) {
if (dep[y] - (1 << i) >= dep[x])
y = p[y][i];
}
if (x == y) return x;
for (ll i = 20; i >= 0; i--) {
if (p[x][i] == p[y][i]) continue;
x = p[x][i], y = p[y][i];
}
return p[x][0];
}
int main()
{
cin >> n >> m; getchar();
for (ll i = 0; i <= n; i++) getline(cin, mp[i], '\n'), mp[i] = " " + mp[i];
for (ll i = 1; i <= n; i++) {
for (ll j = 2; j <= 2 * m + 1; j++) {
if (!(j & 1) && mp[i][j] != '|') add(i, j); // “|” 不能走
}
}
dfs(1, 0); cin >> q;
ll ans = 0;
for (ll i = 1; i <= q; i++) {
ll xi, yi; sc("%lld %lld", &xi, &yi);
c[i] = id(xi, 2 * yi); // 点编号
if (i > 1) {
ll ui = c[i - 1], vi = c[i];
ll lca = LCA(ui, vi);
ans += dis[ui] + dis[vi] - 2 * dis[lca];
}
}
printf("%lld\n", ans);
return 0; // 改数组大小!!!
}