BZOJ2286: [Sdoi2011]消耗战

Posted 嘒彼小星

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ2286: [Sdoi2011]消耗战相关的知识,希望对你有一定的参考价值。

#2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 4833 Solved: 1788 [Submit][Status][Discuss] ##Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。 侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到1号岛屿上)。不过侦查部门还发现了这台机器只能够使用m次,所以我们只需要把每次任务完成即可。 ##Input

第一行一个整数n,代表岛屿数量。

接下来n-1行,每行三个整数u,v,w,代表u号岛屿和v号岛屿由一条代价为c的桥梁直接相连,保证1<=u,v<=n且1<=c<=100000。

第n+1行,一个整数m,代表敌方机器能使用的次数。

接下来m行,每行一个整数ki,代表第i次后,有ki个岛屿资源丰富,接下来k个整数h1,h2,…hk,表示资源丰富岛屿的编号。

##Output

输出有m行,分别代表每次任务的最小代价。

##Sample Input 10

1 5 13

1 9 6

2 1 19

2 4 8

2 3 91

5 6 8

7 5 4

7 8 31

10 7 9

3

2 10 6

4 5 7 8 3

3 9 4 6 ##Sample Output 12

32

22 ##HINT

对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

#题解 $dp[i]$表示以$i$为根的子树,使黑点不与$i$连通的最小割边权值和。 转移有

$$i \ \ \ is \ \ \ white : dp[i]\ =\ min(mi[i], \sum dp[son_i])$$ 其中$mi[i]$表示点i到根的路径上的最小边权 题目有$\sum_{i=1}^{k}k_i \leq 10^5$ 所以用虚树即可,可以证明点数是$n\log_n$级别的 [如何建虚树](http://blog.csdn.net/lych_cys/article/details/50814948 "如何建虚树") 注意不要每次都清空图,否则复杂度退化为nm会T的 记录下那些head需要被清0,同时不要全部开longlong,longlong真心慢,会T ``` #include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <algorithm> #include <map> #include <cmath> inline long long max(long long a, long long b){return a > b ? a : b;} inline long long min(long long a, long long b){return a < b ? a : b;} inline long long abs(long long x){return x < 0 ? -x : x;} inline void swap(int &x, int &y){long long tmp = x;x = y;y = tmp;} template <class T> inline void read(T &x) { x = 0;char ch = getchar(), c = ch; while(ch < ‘0‘ || ch > ‘9‘) c = ch, ch = getchar(); while(ch <= ‘9‘ && ch >= ‘0‘) x = x * 10 + ch - ‘0‘, ch = getchar(); if(c == ‘-‘) x = -x; } const long long INF = 0x3f3f3f3f3f3f3f3f; const int MAXN = 250000 + 10; //Tree struct Edge { int u,v,nxt; long long w; Edge(int _u, int _v, long long _w, int _nxt){u = _u, v = _v, w = _w, nxt = _nxt;} Edge(){} }edge1[MAXN << 1], edge2[MAXN << 1]; int head1[MAXN << 1], head2[MAXN << 1], cnt1, cnt2, deep[MAXN], p[30][MAXN], dfn[MAXN], tt, M, n, m; long long mi[MAXN]; int node[MAXN], tot, stack[MAXN * 20], top, tag[MAXN], re[MAXN], pt; inline void insert1(int a, int b, long long c) { edge1[++ cnt1] = Edge(a, b, c, head1[a]), head1[a] = cnt1; edge1[++ cnt1] = Edge(b, a, c, head1[b]), head1[b] = cnt1; } inline void insert2(int a, int b, long long c = 0) { edge2[++ cnt2] = Edge(a, b, c, head2[a]), head2[a] = cnt2; re[++ pt] = a; } void dfs(int x) { dfn[x] = ++ tt; for(int pos = head1[x];pos;pos = edge1[pos].nxt) { int v = edge1[pos].v; if(v == p[0][x]) continue; deep[v] = deep[x] + 1, mi[v] = min(mi[x], edge1[pos].w), p[0][v] = x; dfs(v); } } void yuchuli() { while((1 << M) <= n) ++ M;-- M; for(int i = 1;i <= M;++ i) for(int j = 1;j <= n;++ j) p[i][j] = p[i - 1][p[i - 1][j]]; } int LCA(int va, int vb) { if(deep[va] < deep[vb]) swap(va, vb); for(int i = M;i >= 0;-- i) if(deep[va] - deep[vb] >= (1 << i)) va = p[i][va]; if(va == vb) return va; for(int i = M;i >= 0;-- i) if(p[i][va] != p[i][vb]) va = p[i][va], vb = p[i][vb]; return p[0][va]; } //Virtual Tree bool cmp(int a, int b) { return dfn[a] < dfn[b]; } void build_VT() { cnt2 = pt = top = 0; std::sort(node + 1, node + 1 + tot, cmp); for(int i = 1;i <= tot;++ i) { if(top == 0) { stack[++ top] = node[i]; continue; } int lca = LCA(stack[top], node[i]); while(deep[lca] < deep[stack[top]]) { if(deep[lca] >= deep[stack[top - 1]]) { insert2(lca, stack[top]); if(stack[-- top] != lca) stack[++ top] = lca; break; } insert2(stack[top - 1], stack[top]), -- top; } stack[++ top] = node[i]; } while(top > 1) insert2(stack[top - 1], stack[top]), -- top; } //DP long long dp[MAXN]; void DP(int x, int pre) { long long sum = 0; for(int pos = head2[x];pos;pos = edge2[pos].nxt) { int v = edge2[pos].v; DP(v, x); sum += dp[v]; } if(tag[x] || !sum) dp[x] = mi[x]; else dp[x] = min(mi[x], sum); } int main() { memset(mi, 0x3f, sizeof(mi)), memset(dp, 0x3f, sizeof(dp)); read(n); for(int i = 1;i < n;++ i) { int tmp1, tmp2; long long tmp3; read(tmp1), read(tmp2), read(tmp3); insert1(tmp1, tmp2, tmp3); } dfs(1);yuchuli(); read(m); for(int i = 1;i <= m;++ i) { read(tot); for(int j = 1;j <= tot;++ j) read(node[j]), tag[node[j]] = 1; build_VT(), DP(stack[1], -1); for(int j = 1;j <= tot;++ j) tag[node[j]] = 0; for(int i = 1;i <= pt;++ i) head2[re[i]] = 0; printf("%lld\n", dp[stack[1]]); } return 0; } ```

以上是关于BZOJ2286: [Sdoi2011]消耗战的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ2286: [Sdoi2011]消耗战

[BZOJ2286][Sdoi2011]消耗战

BZOJ2286[Sdoi2011]消耗战 虚树

bzoj 2286: [Sdoi2011]消耗战

BZOJ2286: [Sdoi2011]消耗战

bzoj2286 [Sdoi2011]消耗战