洛谷P2495 [SDOI2011] 消耗战(虚树+LCA)

题目链接:https://www.luogu.com.cn/problem/P2495

 

[SDOI2011] 消耗战

题目描述

在一场战争中,战场由 $n$ 个岛屿和 $n-1$ 个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为 $1$ 的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他 $k$ 个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。

侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到 $1$ 号岛屿上)。不过侦查部门还发现了这台机器只能够使用 $m$ 次,所以我们只需要把每次任务完成即可。

输入格式

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

接下来 $n-1$ 行,每行三个整数 $u,v,w$ ,表示 $u$ 号岛屿和 $v$ 号岛屿由一条代价为 $w$ 的桥梁直接相连。

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

接下来 $m$ 行,第 $i$ 行一个整数 $k_i$ ,代表第 $i$ 次后,有 $k_i$ 个岛屿资源丰富。接下来 $k_i$ 个整数 $h_1,h_2,..., h_{k_i}$ ,表示资源丰富岛屿的编号。

输出格式

输出共 $m$ 行,表示每次任务的最小代价。

样例 #1

样例输入 #1

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

样例输出 #1

12
32
22

提示

数据规模与约定

  • 对于 $10%$ 的数据,$n\leq 10, m\leq 5$ 。
  • 对于 $20%$ 的数据,$n\leq 100, m\leq 100, 1\leq k_i\leq 10$ 。
  • 对于 $40%$ 的数据,$n\leq 1000, 1\leq k_i\leq 15$ 。
  • 对于 $100%$ 的数据,$2\leq n \leq 2.5\times 10^5, 1\leq m\leq 5\times 10^5, \sum k_i \leq 5\times 10^5, 1\leq k_i< n, h_i\neq 1, 1\leq u,v\leq n, 1\leq w\leq 10^5$ 。

 

 

代码:

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<vector>
  4 #include<map>
  5 #include<queue>
  6 #include<set>
  7 #include<algorithm>
  8 #include<stack>
  9 #include<cmath>
 10 #include<cstring>
 11 #include<string>
 12 using namespace std;
 13 #define int long long
 14 #define gc getchar()
 15 #define rd(x) read(x)
 16 #define el '\n'
 17 #define rep(i, a, n) for(int i = (a); i <= n; ++i)
 18 #define per(i, a, n) for(int i = (a); i >= n; --i)
 19 using ll = long long;
 20 using db = double;
 21 using ldb = long double;
 22 const int N = 500000 + 10;
 23 const int mod = 1e9 + 7;
 24 const int inf = 0x3f3f3f3f;
 25 
 26 template <typename _T>
 27 inline void read(_T& f) {
 28     f = 0; _T fu = 1; char c = gc;
 29     while (c < '0' || c > '9') { if (c == '-') { fu = -1; } c = gc; }
 30     while (c >= '0' && c <= '9') { f = (f << 3) + (f << 1) + (c & 15); c = gc; }
 31     f *= fu;
 32 }
 33 
 34 template <typename T>
 35 void print(T x) {
 36     if (x < 0) putchar('-'), x = -x;
 37     if (x < 10) putchar(x + 48);
 38     else print(x / 10), putchar(x % 10 + 48);
 39 }
 40 
 41 template <typename T>
 42 void print(T x, char t) {
 43     print(x); putchar(t);
 44 }
 45 
 46 struct node {
 47     int to, w, next;
 48 }e[N << 2];
 49 int head[N << 2], tot;
 50 
 51 void ADD(int u, int v, int w) {
 52     e[tot].to = v;
 53     e[tot].w = w;
 54     e[tot].next = head[u];
 55     head[u] = tot++;
 56 }
 57 
 58 void add(int u, int v) {
 59     e[tot].to = v;
 60     //e[tot].w = w;
 61     e[tot].next = head[u];
 62     head[u] = tot++;
 63 }
 64 
 65 int h[N], dfn[N], cnt;
 66 int fa[N][31], dep[N];
 67 int minx[N];
 68 
 69 void dfs(int u, int pre) {
 70     dfn[u] = ++cnt;
 71     fa[u][0] = pre;
 72     dep[u] = dep[pre] + 1;
 73     for (int i = 1; i <= 30; i++) {
 74         fa[u][i] = fa[fa[u][i - 1]][i - 1];
 75     }
 76     for (int i = head[u]; i + 1; i = e[i].next) {
 77         int v = e[i].to;
 78         if (v != pre) {
 79             if (u != 1) minx[v] = min(minx[u], e[i].w);
 80             else minx[v] = e[i].w;
 81             dfs(v, u);
 82         }
 83     }
 84 }
 85 
 86 int lca(int x, int y) {
 87 
 88     if (dep[x] < dep[y]) swap(x, y);
 89     for (int i = 30; i >= 0; i--) {
 90         if ((1 << i) <= dep[x] - dep[y]) x = fa[x][i];
 91     }
 92     if (x == y) return x;
 93     for (int i = 30; i >= 0; i--) {
 94         if (fa[x][i] != fa[y][i]) {
 95             x = fa[x][i];
 96             y = fa[y][i];
 97         }
 98     }
 99 
100     return fa[x][0];
101 }
102 
103 inline bool cmp(const int x, const int y) {
104     return dfn[x] < dfn[y];
105 }
106 
107 int stk[N], top, k;
108 int n, m;
109 
110 void build() {
111     sort(h + 1, h + 1 + k, cmp);
112     stk[top = 1] = 1, head[1] = -1;
113     for (int i = 1; i <= k; i++) {
114         if (h[i] != 1) {
115             int l = lca(h[i], stk[top]);
116             if (l != stk[top]) {
117                 while (dfn[l] < dfn[stk[top - 1]]) {
118                     add(stk[top - 1], stk[top]), top--;
119                 }
120                 if (dfn[l] != dfn[stk[top - 1]]) {
121                     head[l] = -1;
122                     add(l, stk[top]), stk[top] = l;
123                 }
124                 else add(l, stk[top--]);
125             }
126             head[h[i]] = -1;
127             stk[++top] = h[i];
128         }
129     }
130     for (int i = 1; i < top; i++) {
131         add(stk[i], stk[i + 1]);
132     }
133 }
134 
135 map<int, int>vis;
136 
137 int tree_dp(int u) {
138     int ans = 0;
139     for (int i = head[u]; i + 1; i = e[i].next) {
140         int v = e[i].to;
141         ans += tree_dp(v);
142         /*tree_dp(v);
143         if (vis[v]) dp[u] += minx[v];
144         else dp[u] += min(dp[v], minx[v]);*/
145     }
146     if (u == 1) return ans;
147     if (vis[u]) return minx[u];
148     else return min(ans, minx[u]);
149 }
150 
151 signed main() {
152 
153     //int n, m;
154     cin >> n;
155     memset(head, -1, sizeof(head));
156     for (int i = 1; i < n; i++) {
157         int u, v, w;
158         cin >> u >> v >> w;
159         ADD(u, v, w);
160         ADD(v, u, w);
161     }
162     dfs(1, 1);
163     memset(head, -1, sizeof(head));
164     cin >> m;
165     for (; m; --m) {
166         cin >> k;
167         vis.clear();
168         tot = 0;
169         for (int i = 1; i <= k; i++) {
170             cin >> h[i];
171             vis[h[i]] = 1;
172         }
173         build();
174         //tree_dp(1);
175         cout << tree_dp(1) << el;
176     }
177 
178     return 0;
179 }

 

 
 
posted @ 2022-10-12 20:01  Keyzee  阅读(47)  评论(0编辑  收藏  举报