2021牛客暑期多校训练营8 J、Tree
Tree
https://ac.nowcoder.com/acm/contest/11259/J
题目大意
二人现在站在一棵树上的不同点,现在有成员得分等于这个人走过的路径长度,并且在这棵树上行走有一个特殊的性质,就是从
之后
点将会被删除,并且与
相连的全部边都会被删除。现在他们双方都想让自己的得分减掉对方得分最大化,
起始站在
点,
起始站在
点,问游戏结束
的得分减掉
的得分结果是多少?
Solution
考点:表+对抗搜索
第一我们知道对于之间的最短路径来说,如果有任何一个玩家脱离了这条路径上,那么这时候两名玩家就变成完全独立的两个部分分别走最大值了。
第二就是我们用同一个式子来表示双方都想最大化得分差值的式子。如果我们用代表
的得分,
代表
的得分,所以也就是
想要
最大,
想要
最大,等价于
想要
最小。
对于具体的方案来说,我们用一次求出从
路径上全部的点。
对着这些路径上的点走非的路径可以走的最远距离记为
。
接下来我们用代表
从
点离开可以走的最大距离,这个会等于
也就是从
走到
然后再往下走。
同理我们也用代表
从
点离开可以走的最大距离,这个会等于
也就是从
走到
接着走。
然后我们就去的链上跑对抗搜索,对于任意一个人来说,它可以现在就在这个点离开也可以接着走,直到两人相遇的话就不能越过了,这里我们假设现在是
走,那么我们假设
在
点离开,那么
可以选择的最大值应该是
里面的最大值,这里静态的查询我们用
表可以高效的维护。
剩下的就是两人依次取和
的操作了。
时间复杂度,多出来的
是
表预处理的时间复杂度,对于每次
我们保证每个点一定不会被遍历一次。
const int N = 5e5 + 7; int Log[N], st1[21][N], st2[21][N]; int n, s, t; vector<int> G[N]; bool vis[N], tag[N]; int path[N], path1[N], path2[N], len; bool dfs1(int u, int dep) { vis[u] = 1; if (u == t) { len = dep; path[dep] = u; tag[u] = 1; return true; } for (auto& v : G[u]) { if (vis[v]) continue; if (dfs1(v, dep + 1)) { path[dep] = u; tag[u] = 1; return true; } } return false; } int dfs2(int u, int dep) { vis[u] = 1; int maxi = dep; for (auto& v : G[u]) { if (vis[v] || tag[v]) continue; maxi = max(maxi, dfs2(v, dep + 1)); } return maxi; } int query1(int l, int r) { int x = Log[r - l + 1]; return max(st1[x][l], st1[x][r - (1 << x) + 1]); } int query2(int l, int r) { int x = Log[r - l + 1]; return max(st2[x][l], st2[x][r - (1 << x) + 1]); } int dfs3(int l, int r, int mode) { if (mode == 0) { int now = path1[l] - query2(l + 1, r); if (l + 1 < r) now = max(now, dfs3(l + 1, r, 1));; return now; } else { int now = query1(l, r - 1) - path2[r]; if (l + 1 < r) now = min(now, dfs3(l, r - 1, 0)); return now; } } int solve() { n = read(), s = read(), t = read(); for (int i = 1; i < n; ++i) { int u = read(), v = read(); G[u].push_back(v); G[v].push_back(u); } dfs1(s, 1); memset(vis, 0, sizeof vis); for (int i = 1; i <= len; ++i) { path[i] = dfs2(path[i], 0); // 不沿着 s->t 链还能走多远 } for (int i = 1; i <= len; ++i) { path1[i] = path[i] + i - 1; path2[i] = path[i] + len - i; } Log[1] = 0; for (int i = 2; i < N; ++i) Log[i] = Log[i >> 1] + 1; for (int i = 1; i <= len; ++i) { st1[0][i] = path1[i]; st2[0][i] = path2[i]; } for (int i = 1; i <= Log[len]; ++i) { for (int j = 1; j + (1 << i) - 1 <= len; ++j) { st1[i][j] = max(st1[i - 1][j], st1[i - 1][j + (1 << i - 1)]); st2[i][j] = max(st2[i - 1][j], st2[i - 1][j + (1 << i - 1)]); } } print(dfs3(1, len, 0)); return 1; }
2021牛客暑期多校训练营 文章被收录于专栏
))补题-ing