#2018 German Collegiate Programming Contest (GCPC 18) A (建图 + LCA)

 

题目大意 :

有一个由 "_", “|”, “ ”构成的图,任意两个格子之间的路径是唯一的, 现在有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;  // 改数组大小!!!
}

猜你喜欢

转载自blog.csdn.net/weixin_43851525/article/details/103130010