您的位置:首页 > 其它

BZOJ2286 [Sdoi2011消耗战

2015-01-27 21:19 253 查看
一眼,这不是裸树形dp嘛~

一阵猛敲,敲完发现多组询问。。。额,不会了。。。

围观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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: