BZOJ2286 [Sdoi2011消耗战
2015-01-27 21:19
253 查看
一眼,这不是裸树形dp嘛~
一阵猛敲,敲完发现多组询问。。。额,不会了。。。
围观hzwer,发现这就是虚树嘛!咦、等等,虚树是什么?就是个神奇的东西啦!
构建虚树复杂度是O(k * log(k)),dp的复杂度都是O(k)级别的,由于Σki <= 50W,所以就行了。
构建方法是单调性dp,感觉好神啊!
View Code
(p.s. 700次submit留念O(∩_∩)O)
(p.s.1 感谢卢爷提出复杂度分析的错误Orzzzzzz)
一阵猛敲,敲完发现多组询问。。。额,不会了。。。
围观hzwer,发现这就是虚树嘛!咦、等等,虚树是什么?就是个神奇的东西啦!
构建虚树复杂度是O(k * log(k)),dp的复杂度都是O(k)级别的,由于Σki <= 50W,所以就行了。
构建方法是单调性dp,感觉好神啊!
/************************************************************** Problem: 2286 User: rausen Language: C++ Result: Accepted Time:6148 ms Memory:38896 kb ****************************************************************/ #include <cstdio> #include <algorithm> using namespace std; typedef long long ll; const int N = 250005; const int M = N << 1; const ll inf = (ll) 1e60; struct edge { int next, to, v; edge() {} edge(int _n, int _t, int _v) : next(_n), to(_t), v(_v) {} } e[M]; struct Edge { int next, to; Edge() {} Edge(int _n, int _t) : next(_n), to(_t) {} } E[M]; int first , First , tot; struct tree_node { int fa[19], dep, w; ll mn; } tr ; int n, m, cnt_dfs; int s , top; ll f ; int K; int h , cnt_h; int read() { int x = 0; char ch = getchar(); while (ch < '0' || '9' < ch) ch = getchar(); while ('0' <= ch && ch <= '9') (x *= 10) += ch - '0', ch = getchar(); return x; } inline bool cmp(int a, int b) { return tr[a].w < tr[b].w; } inline void Add_Edges(int x, int y, int z) { e[++tot] = edge(first[x], y, z), first[x] = tot; e[++tot] = edge(first[y], x, z), first[y] = tot; } inline void add_edge(int x, int y) { if (x == y) return; E[++tot] = Edge(First[x], y), First[x] = tot; } #define y e[x].to void dfs(int p) { int x; tr[p].w = ++cnt_dfs; for (x = 1; x <= 18; ++x) tr[p].fa[x] = tr[tr[p].fa[x - 1]].fa[x - 1]; for (x = first[p]; x; x = e[x].next) if (y != tr[p].fa[0]) { tr[y].mn = min(tr[p].mn, (ll) e[x].v); tr[y].dep = tr[p].dep + 1; tr[y].fa[0] = p; dfs(y); } } #undef y inline int get_lca(int x, int y) { int i; if (tr[x].dep < tr[y].dep) swap(x, y); for (i = 18; ~i; --i) if (tr[tr[x].fa[i]].dep >= tr[y].dep) x = tr[x].fa[i]; if (x == y) return x; for (i = 18; ~i; --i) if (tr[x].fa[i] != tr[y].fa[i]) x = tr[x].fa[i], y = tr[y].fa[i]; return tr[x].fa[0]; } #define y E[x].to void dp(int p) { ll tmp = 0; int x; for (x = First[p]; x; x = E[x].next) dp(y), tmp += f[y]; First[p] = 0; f[p] = (tmp != 0 && tmp <= tr[p].mn ? tmp : tr[p].mn); } #undef y void work() { int i, now, lca; K = read(), tot = 0; for (i = 1; i <= K; ++i) h[i] = read(); sort(h + 1, h + K + 1, cmp); for (cnt_h = 1, i = 2; i <= K; ++i) if (get_lca(h[cnt_h], h[i]) != h[cnt_h]) h[++cnt_h] = h[i]; s[top = 1] = 1; for (i = 1; i <= cnt_h; ++i) { now = h[i], lca = get_lca(now, s[top]); while (1) { if (tr[lca].dep >= tr[s[top - 1]].dep) { add_edge(lca, s[top--]); if (s[top] != lca) s[++top] = lca; break; } add_edge(s[top - 1], s[top]); --top; } if (s[top] != now) s[++top] = now; } while (--top) add_edge(s[top], s[top + 1]); dp(1); printf("%lld\n", f[1]); } int main() { int i, x, y, z; n = read(); for (i = 1; i < n; ++i) { x = read(), y = read(), z = read(); Add_Edges(x, y, z); } tr[1].mn = inf, tr[1].dep = 1; dfs(1); m = read(); while (m--) work(); return 0; }
View Code
(p.s. 700次submit留念O(∩_∩)O)
(p.s.1 感谢卢爷提出复杂度分析的错误Orzzzzzz)
相关文章推荐
- bzoj2286[Sdoi2011消耗战
- [BZOJ2286][SDOI2011]消耗战
- bzoj 2286: [Sdoi2011]消耗战
- bzoj 2286: [Sdoi2011消耗战
- BZOJ2286:[SDOI2011]消耗战——题解
- 【bzoj2286】【sdoi2011】【消耗战】【虚树+dp】
- 【虚树+树形DP】BZOJ2286(Sdoi2011)[消耗战]题解
- 【bzoj2286】[Sdoi2011消耗战 虚树+dp
- BZOJ 2286: [Sdoi2011]消耗战
- [BZOJ2286][SDOI2011]消耗战
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
- 【BZOJ】2286 [Sdoi2011]消耗战 树形DP+虚树
- bzoj 2286: [Sdoi2011]消耗战 虚树 DP
- [BZOJ2286][SDOI2011]消耗战(虚树+树形DP)
- [SDOI2011][bzoj2286] 消耗战 [虚树+dp]
- BZOJ2286: [Sdoi2011]消耗战
- [Bzoj2286][Sdoi2011]消耗战(虚树模板题附讲解)
- bzoj千题计划254:bzoj2286: [Sdoi2011]消耗战
- 【BZOJ2286】【SDOI2011】消耗战
- bzoj2286 [Sdoi2011]消耗战 单调栈+lca