目录

P2495-[SDOI2011]消耗战

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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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:

1
2
3
12
32
22

思路:

实现:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
#include "ybwhead/ios.h"
int n;
const int maxn = 5e5 + 10;
struct Edge
{
    struct Edge_node
    {
        int v, nxt;
        long long w;
    } e[maxn << 1];
    // #ifndef maxn
    //     const int maxn = (int)1e5 + 100;
    // #endif
    int head[maxn], tot;
    void __ADD(int u, int v, long long w)
    {
        e[++tot] = (Edge_node){v, head[u], w};
        head[u] = tot;
    }
    void add(int u, int v)
    {
        __ADD(u, v, 1);
        __ADD(v, u, 1);
    }
    void add(int u, int v, int w)
    {
        __ADD(u, v, w);
        __ADD(v, u, w);
    }
} e, e1;
int f[maxn << 1][20];
int num, dfn[maxn];
int dep[maxn];
int lg[maxn << 1];
long long mv[maxn];
void dfs(int u, int fa)
{
    dfn[u] = ++num;
    dep[u] = dep[fa] + 1;
    f[num][0] = u;
    for (int i = e.head[u]; i; i = e.e[i].nxt)
    {
        int v = e.e[i].v;
        if (v == fa)
            continue;
        mv[v] = min(mv[u], e.e[i].w);
        dfs(v, u);
        f[++num][0] = u;
    }
}
int calc(int x, int y)
{
    return dep[x] < dep[y] ? x : y;
}
void pre()
{
    for (int i = 2; i <= num; i++)
        lg[i] = lg[i >> 1] + 1;
    for (int j = 1; j <= 18; j++)
    {
        for (int i = 1; i <= num - (1 << j) + 1; i++)
        {
            f[i][j] = calc(f[i][j - 1], f[i + (1 << (j - 1))][j - 1]);
        }
    }
}
int lca(int x, int y)
{
    int l = dfn[x], r = dfn[y];
    if (l > r)
        swap(l, r);
    return calc(f[l][lg[r - l + 1]], f[r - (1 << lg[r - l + 1]) + 1][lg[r - l + 1]]);
}
int k, v[maxn];
int q[maxn];
int cmp(int a, int b)
{
    return dfn[a] < dfn[b];
}
int s[maxn], top;
long long dfs1(int u, int fa)
{
    long long sum = 0;
    long long tmp;
    for (int i = e1.head[u]; i; i = e1.e[i].nxt)
    {
        int v = e1.e[i].v;
        // yout << v << "!!!" << i << endl;
        if (v == fa)
            continue;
        sum += dfs1(v, u);
    }
    // cout << u << " " << mv[u] << " " << sum << endl;
    if (q[u])
        tmp = mv[u];
    else
        tmp = min((long long)mv[u], sum);
    q[u] = 0;
    e1.head[u] = 0;
    return tmp;
}
long long work()
{
    for (int i = 1; i <= k; i++)
        q[v[i]] = 1;
    sort(v + 1, v + k + 1, cmp);
    s[top = 1] = v[1];
    for (int i = 2; i <= k; i++)
    {
        int now = v[i];
        int lc = lca(now, s[top]);
        // yout << now << endl;
        while (1)
        {
            if (dep[lc] >= dep[s[top - 1]])
            {
                if (lc != s[top])
                {
                    e1.add(lc, s[top]);
                    if (lc != s[top - 1])
                        s[top] = lc;
                    else
                        top--;
                }
                break;
            }
            else
            {
                e1.add(s[top - 1], s[top]);
                top--;
            }
        }
        s[++top] = now;
    }
    // yout << top << endl;
    // yout << s[top] << ' ' << s[top - 1] << endl;
    while (--top)
        e1.add(s[top], s[top + 1]);
    return dfs1(s[1], 0);
}
int main()
{
    yin >> n;
    mv[1] = LLONG_MAX / 10;
    for (int i = 1; i < n; i++)
    {
        int u, v;
        long long w;
        yin >> u >> v >> w;
        e.add(u, v, w);
    }
    dfs(1, 0);
    // yout << dep[0] << endl;
    pre();
    // yout << dep[0] << endl;
    int m;
    yin >> m;
    while (m--)
    {
        // int k;
        yin >> k;
        for (int i = 1; i <= k; i++)
            yin >> v[i];
        // yout << dep[0] << endl;
        yout << work() << endl;
        e1.tot = 0;
    }
    return 0;
}