Description
在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。
侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。
Solution
算是很基础的虚树题了吧,都不要存边权。
对于每次询问建出虚树,然后树形DP即可。
我们建虚树之前可以对点进行处理:如果一个是另一个的祖先,那么将深度较大的那个点删去。这样可以方便DP。
Source
/************************************************
* Au: Hany01
* Date: Apr 1st, 2018
* Prob: [BZOJ2286][SDOI2011] 消耗战
* Email: hany01@foxmail.com
************************************************/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
#define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define rep(i, j) for (register int i = 0, i##_end_ = (j); i < i##_end_; ++ i)
#define For(i, j, k) for (register int i = (j), i##_end_ = (k); i <= i##_end_; ++ i)
#define Fordown(i, j, k) for (register int i = (j), i##_end_ = (k); i >= i##_end_; -- i)
#define Set(a, b) memset(a, b, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define x first
#define y second
#define pb(a) push_back(a)
#define mp(a, b) make_pair(a, b)
#define ALL(a) (a).begin(), (a).end()
#define SZ(a) ((int)(a).size())
#define INF (0x3f3f3f3f)
#define INF1 (2139062143)
#define Mod (1000000007)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define y1 wozenmezhemecaia
#define oo (1000000000000000000ll)
template <typename T> inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
template <typename T> inline bool chkmin(T &a, T b) { return b < a ? a = b, 1 : 0; }
inline int read()
{
register int _, __; register char c_;
for (_ = 0, __ = 1, c_ = getchar(); c_ < '0' || c_ > '9'; c_ = getchar()) if (c_ == '-') __ = -1;
for ( ; c_ >= '0' && c_ <= '9'; c_ = getchar()) _ = (_ << 1) + (_ << 3) + (c_ ^ 48);
return _ * __;
}
const int maxn = 250005;
int las[maxn], e, v[maxn << 1], w[maxn << 1], nex[maxn << 1], beg[maxn], dfn[maxn], dep[maxn], fa[maxn][19], tim;
LL dp[maxn], val[maxn];
vector<int> Next[maxn];
inline void add(int uu, int vv, int ww) { v[++ e] = vv, w[e] = ww, nex[e] = beg[uu], beg[uu] = e; }
inline void ADD(int u, int v, int id)
{
if (u == v) return ;
if (las[u] != id) las[u] = id, Next[u].clear();
if (las[v] != id) las[v] = id, Next[v].clear();
Next[u].pb(v);
}
void dfs(int u, int pa)
{
dfn[u] = ++ tim, dep[u] = dep[pa] + 1, fa[u][0] = pa;
for (register int i = beg[u]; i; i = nex[i]) if (v[i] != pa)
val[v[i]] = min(val[u], (LL)w[i]), dfs(v[i], u);
}
inline int LCA(int u, int v)
{
if (dep[u] < dep[v]) swap(u, v);
Fordown(i, 17, 0)
if (dep[u] - (1 << i) >= dep[v]) u = fa[u][i];
if (u == v) return u;
Fordown(i, 17, 0) if (fa[u][i] != fa[v][i]) u = fa[u][i], v = fa[v][i];
return fa[u][0];
}
inline bool cmp(const int& A, const int& B) { return dfn[A] < dfn[B]; }
void DP(int u)
{
register LL tmp = 0;
register int sz = SZ(Next[u]);
dp[u] = val[u];
if (!sz) return ;
rep(i, sz) DP(Next[u][i]), tmp += dp[Next[u][i]];
chkmin(dp[u], tmp);
}
int main()
{
#ifdef hany01
File("bzoj2286");
#endif
//Init
static int n, uu, vv, ww, s[maxn], stk[maxn];
n = read();
For(i, 2, n) uu = read(), vv = read(), ww = read(), add(uu, vv, ww), add(vv, uu, ww);
val[1] = oo, dfs(1, 0);
for (int j = 1; (1 << j) <= n; ++ j)
For(i, 1, n) fa[i][j] = fa[fa[i][j - 1]][j - 1];
//Solve
for (static int m = read(); m --; )
{
register int tot = read(), top, cnt = 1;
For(i, 1, tot) s[i] = read();
sort(s + 1, s + 1 + tot, cmp);
For(i, 2, tot) if (LCA(s[cnt], s[i]) != s[cnt]) s[++ cnt] = s[i];
tot = cnt;
stk[top = 1] = 1;
For(i, 1, tot)
{
register int u = s[i], lca = LCA(u, stk[top]);
if (lca == stk[top]) stk[++ top] = u;
else {
while (top >= 2 && dep[stk[top - 1]] > dep[lca])
ADD(stk[top - 1], stk[top], m + 1), -- top;
if (stk[top] != lca) ADD(lca, stk[top], m + 1), stk[top] = lca;
stk[++ top] = u;
}
}
For(i, 1, top - 1) ADD(stk[i], stk[i + 1], m + 1);
DP(1);
printf("%lld\n", dp[1]);
}
return 0;
}