zoukankan      html  css  js  c++  java
  • BZOJ2286: [Sdoi2011]消耗战

    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,复杂度O(nm)

    引入新姿势:虚树,考虑sigma(ki)很小,建出虚树:只有用到的点和他们的LCA

    然后虚树上DP即可

    代码如下:

    //MT_LI
    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f*=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
        return x*f;
    }
    struct node{
        int x,y,d,next;
    }a[510000],e[510000];int elen,len,last[510000],first[510000];
    void ins(int x,int y,int d)
    {
        len++;
        a[len].x=x;a[len].y=y;a[len].d=d;
        a[len].next=last[x];last[x]=len;
    }
    void add(int x,int y)
    {
        elen++;
        e[elen].x=x;e[elen].y=y;
        e[elen].next=first[x];first[x]=elen;
    }
    typedef long long ll;
    ll v[510000];
    int id[510000],cnt;
    int bin[25],f[510000][25],dep[510000];
    void dfs(int x,int fa)
    {
        id[x]=++cnt;
        dep[x]=dep[fa]+1;f[x][0]=fa;
        for(int i=1;bin[i]<=dep[x];i++)f[x][i]=f[f[x][i-1]][i-1];
        for(int k=last[x];k;k=a[k].next)
        {
            int y=a[k].y;
            if(y!=fa)
            {
                v[y]=min(v[x],(ll)a[k].d);
                dfs(y,x);
            }
        }
    }
    int LCA(int x,int y)
    {
        if(dep[x]<dep[y])swap(x,y);
        for(int i=20;i>=0;i--)
            if(dep[x]-bin[i]>=dep[y])
                x=f[x][i];
        if(x==y)return x;
        for(int i=20;i>=0;i--)
            if(f[x][i]!=f[y][i])
                x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    bool cmp(int x,int y){return id[x]<id[y];}
    int k,p[510000],top,sta[510000];
    void build()
    {
        sort(p+1,p+k+1,cmp);
        int tp=1;
        for(int i=2;i<=k;i++)if(LCA(p[tp],p[i])!=p[tp])p[++tp]=p[i];
        k=tp;
        top=0;sta[++top]=1;
        for(int i=1;i<=k;i++)
        {
            int lca=LCA(p[i],sta[top]);
            while(1)
            {
                if(dep[lca]>=dep[sta[top-1]])
                {
                    if(lca!=sta[top])add(lca,sta[top]);
                    top--;
                    if(lca!=sta[top])sta[++top]=lca; 
                    break;
                }
                add(sta[top-1],sta[top]);top--;
            }
            if(p[i]!=sta[top])sta[++top]=p[i];
        }
        top--;
        while(top){add(sta[top],sta[top+1]);top--;}
    }
    ll dp[510000];
    void treedp(int x)
    {
        ll ans=0;dp[x]=v[x];
        for(int k=first[x];k;k=e[k].next)
        {
            int y=e[k].y;
            treedp(y);ans+=dp[y];
        }
        first[x]=0;
        if(ans)dp[x]=min(dp[x],ans);
    }
    int main()
    {
        bin[0]=1;for(int i=1;i<=24;i++)bin[i]=bin[i-1]<<1;
        int n=read();
        len=0;memset(last,0,sizeof(last));
        for(int i=1;i<n;i++)
        {
            int x,y,d;
            x=read();y=read();d=read();
            ins(x,y,d);ins(y,x,d);
        }
        cnt=0;dep[1]=1;v[1]=1ll<<60;dfs(1,0);
        int m=read();
        while(m--)
        {
            k=read();
            for(int i=1;i<=k;i++)p[i]=read();
            elen=0;build();treedp(1);
            printf("%lld
    ",dp[1]);
        }
        return 0;
    }
  • 相关阅读:
    AttributeError: 'DatasetV1Adapter' object has no attribute 'group_by_window'版本兼容问题解决
    Jupyter kernel管理
    AttributeError: module 'tensorflow_core._api.v2.nn' has no attribute 'rnn_cell' tensorflow版本兼容问题-解决
    在虚拟机Linux中安装VMTools遇到的问题-小结
    VuGen总结
    Controller控制器
    事物
    loadrunner参数化
    编写get和post请求
    loadrunner组成
  • 原文地址:https://www.cnblogs.com/MT-LI/p/10063652.html
Copyright © 2011-2022 走看看