Codeforces 348E 树的中心点的性质 / 树形DP / 点分治
Posted pkgunboat
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces 348E 树的中心点的性质 / 树形DP / 点分治相关的知识,希望对你有一定的参考价值。
题意及思路:http://ydc.blog.uoj.ac/blog/12
在求出树的直径的中心后,以它为根,对于除根以外的所有子树,求出子树中的最大深度,以及多个点的最大深度的lca,因为每个点的最长路径一定经过根,所以找到最大深度的子树,然后在这个点和最大深度的lca上树上差分一下就好了。注意,此处的中心是sum / 2处的那个点(sum是直径的长度)
代码:
#include <bits/stdc++.h> #define pii pair<int, int> using namespace std; const int maxn = 100010; int f[maxn]; int d[maxn]; vector<pii> G[maxn]; int mx[maxn], mx_pos[maxn], dye[maxn], sum[maxn]; int v[maxn]; int ans, ans_cnt, root, pos, n, m; void add(int x, int y, int z) G[x].push_back(make_pair(y, z)); G[y].push_back(make_pair(x, z)); bool dfs(int x, int fa, int now) int flag = (v[x] == 1); d[x] = now; for (auto y : G[x]) if(y.first == fa) continue; int tmp = dfs(y.first, x, now + y.second); flag |= tmp; f[y.first] = x; if(flag && d[x] > ans) ans = d[x]; pos = x; return flag; void get_root() dfs(1, -1, 0); memset(d, 0, sizeof(d)); ans = 0; root = pos; dfs(root, -1, 0); int Sum = d[pos], tmp = pos; while(d[tmp] > d[pos] / 2) tmp = f[tmp]; root = tmp; void update(int pos, int ch, int val) if(mx[pos] < mx[ch] + val) mx[pos] = mx[ch] + val; mx_pos[pos] = mx_pos[ch]; else if(mx[pos] == mx[ch] + val) mx_pos[pos] = pos; bool dfs1(int x, int fa, int color) dye[x] = color; int flag = (v[x] == 1); if(flag == 1) mx_pos[x] = x; for (auto y : G[x]) if(y.first == fa) continue; int tmp; tmp = dfs1(y.first, x, color); f[y.first] = x; if(tmp) update(x, y.first, y.second); flag |= tmp; return flag; void dfs2(int x, int fa) for (auto y : G[x]) if(y.first == fa) continue; dfs2(y.first, x); sum[x] += sum[y.first]; if(sum[x] > ans && v[x] == 0) ans = sum[x]; ans_cnt = 1; else if(sum[x] == ans && v[x] == 0) ans_cnt++; vector<pii> res; map<int, int> mp; set<int> s; int tot; void solve() for (auto y : G[root]) int tmp = dfs1(y.first, root, ++tot); if(tmp) res.push_back(make_pair(mx[y.first] + y.second, mx_pos[y.first])); if(v[root] == 1) res.push_back(make_pair(0, root)); sort(res.begin(), res.end()); s.insert(dye[res[res.size() - 1].second]); for (int i = res.size() - 1; i >= 1; i--) if(res[i].first == res[i - 1].first) s.insert(dye[res[i].second]); s.insert(dye[res[i - 1].second]); else break; for (int i = 0; i < res.size(); i++) mp[res[i].first]++; for (int i = 1; i <= n; i++) if(v[i] == 1) if(s.count(dye[i]) && s.size() > 1) if(s.size() > 2) sum[i]++; else for (int j = res.size() - 1; j >= 0; j--) if(dye[i] != dye[res[j].second]) sum[i]++; sum[res[j].second]++; sum[root]--; break; else if(s.size() > 1) sum[i]++; continue; if(dye[i] != dye[res[res.size() - 1].second]) sum[i]++; sum[res[res.size() - 1].second]++; sum[root]--; else sum[i]++; if(mp[res[res.size() - 2].first] == 1) sum[res[res.size() - 2].second]++; sum[root]--; ans = ans_cnt = 0; dfs2(root, -1); int main() int x, y, z; scanf("%d%d", &n, &m); for (int i = 1; i <= m ;i++) scanf("%d", &x); v[x] = 1; for (int i = 1; i < n; i++) scanf("%d%d%d", &x, &y, &z); add(x, y, z); get_root(); solve(); printf("%d %d\n", ans, ans_cnt);
点分治和树形DP先留个坑。。。。
以上是关于Codeforces 348E 树的中心点的性质 / 树形DP / 点分治的主要内容,如果未能解决你的问题,请参考以下文章
D. Lost Tree树的二分图性质——Codeforces LATOKEN Round 1 (Div. 1 + Div. 2)
D. Lost Tree树的二分图性质——Codeforces LATOKEN Round 1 (Div. 1 + Div. 2)
Codeforces 1005F Berland and the Shortest Paths 最短路树性质
Codeforces 1108F MST Unification(最小生成树性质)