bzoj2286 [Sdoi2011]消耗战

2286: [Sdoi2011]消耗战

Time Limit: 20 Sec  Memory Limit: 512 MB
Submit: 4797  Solved: 1766
[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

分析:学习了一波虚树.

   关于虚树在sengxian的博客中有较为详细的介绍:传送门. 主要想说一下这道题的注意点.

   1.因为是阻断1号点到特殊点的路径,所以如果有特殊点在同一条链上,保留上面的那一个就好了.

   2.连边可能会出现相同的点,要排除掉.

   3.注意一开始要将1号点加入栈中.

   4.最后的dp方程很简单:f[i] = min{Σf[j],f[i]}.f[i]初始化为i这个点到1号点路径的最短边长度. 这个dp方程是什么意思呢?要么把i号点连向儿子的边全都砍掉,要么砍掉祖先的边.

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

typedef long long ll;
const ll maxn = 250010;
const ll inf = 1e17;
ll n,head1[maxn],to1[maxn * 2],nextt1[maxn * 2],tot1 = 1,w1[maxn * 2],m;
ll head2[maxn],to2[maxn * 2],nextt2[maxn * 2],tot2 = 1,w2[maxn * 2];
ll deep[maxn],fa[maxn][20],pos[maxn],dfs_clock,q[maxn],k,tot,sta[maxn],top;
ll f[maxn],d[maxn];

void add1(ll x,ll y,ll z)
{
    w1[tot1] = z;
    to1[tot1] = y;
    nextt1[tot1] = head1[x];
    head1[x] = tot1++;
}

void add2(ll x,ll y)
{
    if (x == y)
        return;
    to2[tot2] = y;
    nextt2[tot2] = head2[x];
    head2[x] = tot2++;
}

ll lca(ll x,ll y)
{
    if (deep[x] < deep[y])
        swap(x,y);
    for (ll i = 19; i >= 0; i--)
        if (deep[fa[x][i]] >= deep[y])
            x = fa[x][i];
    if (x == y)
        return x;
    for (ll i = 19; i >= 0; i--)
        if (fa[x][i] != fa[y][i])
        {
            x = fa[x][i];
            y = fa[y][i];
        }
    return fa[x][0];

}

void dfs(ll u,ll faa)
{
    fa[u][0] = faa;
    pos[u] = ++dfs_clock;
    for (int i = 1; i <= 19; i++)
        fa[u][i] = fa[fa[u][i - 1]][i - 1];
    for (ll i = head1[u]; i; i = nextt1[i])
    {
        ll v = to1[i];
        if (v == faa)
            continue;
        d[v] = min(d[u],w1[i]);
        deep[v] = deep[u] + 1;
        dfs(v,u);
    }
}

bool cmp(ll x,ll y)
{
    return pos[x] < pos[y];
}

void dp(ll u)
{
    ll res = 0;
    f[u] = d[u];
    for (ll i = head2[u]; i; i = nextt2[i])
    {
        ll v = to2[i];
        dp(v);
        res += f[v];
    }
    head2[u] = 0;
    if (!res)
        f[u] = d[u];
    else if (res < f[u])
        f[u] = res;
}

void solve()
{
    scanf("%lld",&k);
    for (ll i = 1; i <= k; i++)
        scanf("%lld",&q[i]);
    sort(q + 1,q + 1 + k,cmp);
    tot = 0;
    q[++tot] = q[1];
    for (ll i = 2; i <= k; i++)
        if (lca(q[tot],q[i]) != q[tot])
            q[++tot] = q[i];
    top = 0;
    tot2 = 1;
    sta[++top] = 1;
    for (ll i = 1; i <= tot; i++)
    {
        ll LCA = lca(q[i],sta[top]);while (1)
            {
                if (deep[sta[top - 1]] <= deep[LCA])
                {
                    add2(LCA,sta[top]);
                    top--;
                    if (sta[top] != LCA)
                        sta[++top] = LCA;
                    break;
                }
                add2(sta[top - 1],sta[top]);
                top--;
            }
            if (sta[top] != q[i])
                sta[++top] = q[i];
    }
    top--;
    while (top)
    {
        add2(sta[top],sta[top + 1]);
        top--;
    }
    dp(1);
    printf("%lld\n",f[1]);
}

int main()
{
    scanf("%lld",&n);
    for (ll i = 1; i < n; i++)
    {
        ll u,v,w;
        scanf("%lld%lld%lld",&u,&v,&w);
        add1(u,v,w);
        add1(v,u,w);
    }
    d[1] = inf;
    deep[1] = 1;
    dfs(1,0);
    scanf("%lld",&m);
    while (m--)
        solve();

    return 0;
}

 

posted @ 2018-03-03 14:39  zbtrs  阅读(177)  评论(0编辑  收藏  举报