HDU5449 Robot Dog

题目蓝链

Description

给你一棵树,经过一条边的时间为\(1\)。有\(q\)次询问,每次询问给定一条有若干个关键点的路径,你需要依次经过这些关键点。你会从路径的起点开始,每次随机选择一条与当前点直接相连的边走过去。问你走完这条路径的期望时间为多少

Solution

首先,本题有这样一个性质(在树上)

对于任意一条链\((x, y)\),我们在链上任意取一个点\(k\),均满足\(dis(x, k) + dis(k, y) = dis(x, y)\),其中\(dis(x, y)\)表示\(x\)点到\(y\)的期望时间

我们可以任选一个点作为根,然后预处理出两个数组\(up[i], down[i]\),分别表示\(i\)号点到它父亲需要的期望时间以及\(i\)号点父亲到它所需要的期望时间

然后我们就可以维护\(up\)\(down\)的树上前缀和就可以求出任意一条路径的期望时间了

下面是一种比较简单的求出\(up\)\(down\)的方法,\(size[i]\)表示以\(i\)为根的子树大小

\[up[i] = 2 \cdot size[i] - 1 \\ down[i] = 2 \cdot (n - size[i]) - 1 \]

还有一种比较容易理解,但理解比较麻烦的办法 传送门

Code

#include <bits/stdc++.h>

using namespace std;

#define fst first
#define snd second
#define mp make_pair
#define squ(x) ((LL)(x) * (x))
#define debug(...) fprintf(stderr, __VA_ARGS__)

typedef long long LL;
typedef pair<int, int> pii;

template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }

inline int read() {
	int sum = 0, fg = 1; char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') fg = -1;
	for (; isdigit(c); c = getchar()) sum = (sum << 3) + (sum << 1) + (c ^ 0x30);
	return fg * sum;
}

const int maxn = 5e4 + 10;

vector<int> g[maxn];

int n, m, d[maxn], sz[maxn], fa[maxn][16];

inline void dfs(int now, int f) {
	sz[now] = 1, d[now] = d[f] + 1, fa[now][0] = f;
	for (int i = 1; i <= 15; i++) fa[now][i] = fa[fa[now][i - 1]][i - 1];
	for (int i = 0; i < g[now].size(); i++) {
		int son = g[now][i];
		if (son == f) continue;
		dfs(son, now);
		sz[now] += sz[son];
	}
}

LL up[maxn], dn[maxn];
inline void DFS(int now, int f) {
	up[now] = (sz[now] << 1) - 1, dn[now] = ((n - sz[now]) << 1) - 1;
	up[now] += up[f], dn[now] += dn[f];
	for (int i = 0; i < g[now].size(); i++) {
		int son = g[now][i];
		if (son == f) continue;
		DFS(son, now);
	}
}

inline int lca(int x, int y) {
	if (d[x] < d[y]) swap(x, y);
	for (int i = 15; ~i; i--)
		if (d[fa[x][i]] >= d[y]) x = fa[x][i];
	if (x == y) return x;
	for (int i = 15; ~i; i--)
		if (fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i];
	return fa[x][0];
}

inline LL dis(int x, int y) {
	int LCA = lca(x, y);
	return up[x] - up[LCA] + dn[y] - dn[LCA];
}

int main() {
	freopen("C.in", "r", stdin);
	freopen("C.out", "w", stdout);

	int T = read();
	while (T--) {
		n = read();
		for (int i = 1; i <= n; i++) g[i].clear();
		for (int i = 1; i < n; i++) {
			int x = read() + 1, y = read() + 1;
			g[x].push_back(y), g[y].push_back(x);
		}
		dfs(1, 0), DFS(1, 0);
		m = read();
		for (int i = 1; i <= m; i++) {
			LL ans = 0;
			int cnt = read(), lst = read() + 1;
			for (int j = 1; j <= cnt; j++) {
				int now = read() + 1;
				ans += dis(lst, now);
				lst = now;
			}
			printf("%lld.0000\n", ans);
		}
		if (T) printf("\n");
	}

	return 0;
}
posted @ 2019-01-27 20:56  xunzhen  阅读(140)  评论(0编辑  收藏  举报