zoukankan      html  css  js  c++  java
  • 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
    ",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;
    }
  • 相关阅读:
    很好的理解遗传算法的样例
    基于注解Spring MVC综合Hibernate(需要jar包,spring和Hibernate整合配置,springMVC组态,重定向,)批量删除
    Caused by: java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory
    运行时间(Java版本)—转换毫秒到时分秒日期
    提高团队代码质量
    do...while(0)神奇
    &quot;错: void 值不被忽略,因为预期&quot;解决
    [全国首发]Swift视频教程
    CSS3新功能简要
    Android物业动画研究(Property Animation)彻底解决具体解释
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8496664.html
Copyright © 2011-2022 走看看