codevs1218: [NOIP2012]疫情控制
2016-10-24 21:52
267 查看
题目链接
在一个有n个节点的带权树上除根节点外的某些节点驻扎着共m个军队。令这些军队沿着树边移动,最终使得每条从根节点到叶子节点的路径上(根节点除外)至少驻扎有1个军队,求所有军队移动的总路程的最小值。
很容易想到二分答案判断可行性,移动策略如下。
在给定移动距离上限的情况下,尽量向上移动是最优的,除在根节点以外的向下移动都是无意义的。只向上移动而不经过根节点的情况可以直接用倍增解决,然而经过根节点的情况需要进一步使用贪心决策。排序后依次判断,若该军队所处路径没有被覆盖,则直接覆盖该路径,否则判断是否可覆盖其他未被覆盖的离根节点最近的路径。
贴上调了一下午的丑比代码。
这是一篇意义不明的无良题解,蒟蒻博主只是想吐槽这道题的变态出题人。
在一个有n个节点的带权树上除根节点外的某些节点驻扎着共m个军队。令这些军队沿着树边移动,最终使得每条从根节点到叶子节点的路径上(根节点除外)至少驻扎有1个军队,求所有军队移动的总路程的最小值。
很容易想到二分答案判断可行性,移动策略如下。
在给定移动距离上限的情况下,尽量向上移动是最优的,除在根节点以外的向下移动都是无意义的。只向上移动而不经过根节点的情况可以直接用倍增解决,然而经过根节点的情况需要进一步使用贪心决策。排序后依次判断,若该军队所处路径没有被覆盖,则直接覆盖该路径,否则判断是否可覆盖其他未被覆盖的离根节点最近的路径。
贴上调了一下午的丑比代码。
#include <vector> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int N = 50050, H = 16; typedef long long ll; inline int read() { char c = getchar(); int rst = 0; while (c < '0' or c > '9') c = getchar(); while (c >= '0' and c <= '9') { rst *= 10; rst += c - '0'; c = getchar(); } return rst; } struct edge{ int v, w; edge(int __v, int __w): v(__v), w(__w) {} }; vector<edge> E ; int n, m, army , fa ; ll dist , maxDist; void dfs(int u, int f) { fa[u] = f; for (int i = 0; i < E[u].size(); i++) { int v = E[u][i].v, w = E[u][i].w; if (v == f) continue; dist[v] = dist[u] + (ll)w; dfs(v, u); } } int up [H]; inline void initLca() { for (int i = 1; i <= n; i++) up[i][0] = fa[i]; for (int j = 1; j < H; j++) { bool flag = false; for (int i = 1; i <= n; i++) if (up[i][j - 1]) { up[i][j] = up[up[i][j - 1]][j - 1]; flag = true; } if (! flag) break; } } inline int findR(int u) { int p = u; while (fa[p] != 1) { for (int j = 1; j < H; j++) { if (! up[p][j] or up[p][j] == 1) { p = up[p][j - 1]; break; } } } return p; } inline int getFa(int u, ll cap) { if (cap >= dist[u]) return findR(u); int p = u; while (dist[u] - dist[fa[p]] <= cap) { if (dist[u] - dist[fa[p]] == cap) return fa[p]; for (int j = 1; j < H; j++) { if (! up[p][j] or dist[u] - dist[up[p][j]] > cap) { p = up[p][j - 1]; break; } } } return p; } bool mark ; int son , spare , sCnt, need , nCnt; void fill(int u) { if (mark[u]) return; mark[u] = true; if (! fa[u]) return; son[fa[u]]++; if (! mark[fa[u]] and son[fa[u]] == E[fa[u]].size() - 1 + (fa[u] == 1)) fill(fa[u]); } inline bool cmp(int a, int b) { return dist[a] > dist[b]; } inline bool cmp2(int a, int b) { return dist[a] < dist[b]; } inline bool judge(ll cap) { memset(mark, 0, sizeof(mark)); memset(son, 0, sizeof(son)); nCnt = sCnt = 0; for (int i = 1; i <= m; i++) { int now = army[i]; if (dist[now] < cap) { spare[++sCnt] = now; } else { int p = getFa(now, cap); fill(p); } } if (mark[1]) return true; sort(spare + 1, spare + 1 + sCnt, cmp); for (int i = 0; i < E[1].size(); i++) if (! mark[E[1][i].v]) need[++nCnt] = E[1][i].v; sort(need + 1, need + 1 + nCnt, cmp2); for (int i = 1, j = 1; i <= sCnt; i++) { int rt = findR(spare[i]); if (! mark[rt]) fill(rt); else if (cap - dist[spare[i]] >= dist[need[j]]) fill(need[j]); while (mark[need[j]] && j <= nCnt) j++; if (j >= nCnt + 1) return true; } return false; } inline ll work() { if (m < E[1].size()) return -1LL; ll l = 0, r = (maxDist << 1) * m; while (l < r) { ll mid = l + r >> 1; if (judge(mid)) r = mid; else l = mid + 1; } return l; } int main() { n = read(); for (int i = 1; i < n; i++) { int u = read(), v = read(), w = read(); E[u].push_back(edge(v, w)); E[v].push_back(edge(u, w)); } dfs(1, 0); initLca(); m = read(); for (int i = 1; i <= m; i++) { scanf("%d", &army[i]); maxDist = max(maxDist, dist[army[i]]); } printf("%lld\n", work()); return 0; }
这是一篇意义不明的无良题解,蒟蒻博主只是想吐槽这道题的变态出题人。
相关文章推荐
- [NOIP2012][CODEVS1218]疫情控制(二分+倍增+贪心)
- Codevs 1218 疫情控制 2012年NOIP全国联赛提高组
- codevs1218疫情控制--noip2012dayt3
- 洛谷1084/codevs1218 二分+倍增+贪心,疫情控制,分步讲解
- 疫情控制(codevs 1218)
- 【CodeVS 1218】【NOIP 2012】疫情控制
- codevs 1218 疫情控制
- NOIP 2012 疫情控制
- 【NOIP2012】疫情控制
- 【NOIP2012】codevs1217 借教室
- 【NOIP2012】疫情控制
- [noip2012]疫情控制(二分+贪心)
- NOIP2012提高组Day2 第3题 疫情控制
- noip2012 疫情控制
- noip2012 疫情控制
- 【贪心+高精度】NOIP2012D1T2国王游戏Codevs1198
- 【NOIP2012】疫情控制
- [NOIP2012]疫情控制
- 2012Noip提高组Day2 T3 疫情控制
- 【codevs1200】 NOIP2012—同余方程