• bzoj 2286: [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非常好想
    定义f[i]为i的子树内全部摧毁的最小代价。
    f[i]=min(sigma(f[u]),e)     u为i的所有儿子,e为父亲边权值
    那么这样复杂度是O(nm)的
    所以要构建虚树:
    虚树的作用:在对答案无影响的情况下,将无关节点去处,只保留相关节点
    构建思路:大致是用栈维护一条时间戳递增的链,具体方法参见其他博客
     
    然后在上述DP上稍加修改:把e改为(i到根路径上代价最小的即可)   可以预处理出来。
      1 #include <algorithm>
      2 #include <iostream>
      3 #include <cstdlib>
      4 #include <cstring>
      5 #include <cstdio>
      6 #include <cmath>
      7 #define RG register
      8 using namespace std;
      9 typedef long long ll;
     10 const int N=250015,inf=2e8;
     11 int n,head[N],num=1,lim,DFN=0;
     12 struct Lin{
     13     int next,to,dis;
     14 }a[N<<1],e[N<<1];
     15 void addedge(int x,int y,int z){
     16     a[++num].next=head[x];
     17     a[num].to=y;
     18     a[num].dis=z;
     19     head[x]=num;
     20 }
     21 int q[N],dfn[N],dep[N],val[N],fa[N][19];
     22 int Lca(int x,int y){
     23     if(dep[x]<dep[y])swap(x,y);
     24     int deep=dep[x]-dep[y];
     25     for(int i=lim;i>=0;i--)
     26         if((1<<i)&deep)x=fa[x][i];
     27     if(x==y)return x;
     28     for(int i=lim;i>=0;i--){
     29         if(fa[x][i]!=fa[y][i])
     30             x=fa[x][i],y=fa[y][i];
     31     }
     32     return fa[x][0];
     33 }
     34 bool comp(int i,int j){
     35     return dfn[i]<dfn[j];
     36 }
     37 int st[N],H[N],NUM=0;ll f[N];
     38 void init(int x,int y){
     39     if(x==y)return ;
     40     e[++NUM].next=H[x];e[NUM].to=y;H[x]=NUM;
     41     e[++NUM].next=H[y];e[NUM].to=x;H[y]=NUM;
     42 }
     43 void dfs(int x,int last){
     44     RG int u;ll tot=0;
     45     if(x!=1)f[x]=val[x];
     46     else f[x]=2e18;
     47     for(RG int i=H[x];i;i=e[i].next){
     48         u=e[i].to;if(u==last)continue;
     49         dfs(u,x);tot+=f[u];
     50     }
     51     H[x]=0;
     52     if(tot && tot<f[x])f[x]=tot;
     53 }
     54 void solve(){
     55     NUM=0;
     56     int m;scanf("%d",&m);
     57     for(RG int i=1;i<=m;i++)scanf("%d",&q[i]);
     58     sort(q+1,q+m+1,comp);
     59     int s=1;
     60     for(RG int i=2;i<=m;i++)if(Lca(q[i],q[s])!=q[s])q[++s]=q[i];
     61     int top=0,lca;
     62     st[++top]=1;
     63     for(RG int i=1;i<=s;i++){
     64         lca=Lca(q[i],st[top]);
     65         while(1){
     66             if(dep[st[top-1]]<=dep[lca]){
     67                 init(st[top],lca);top--;
     68                 if(st[top]!=lca)st[++top]=lca;
     69                 break;
     70             }
     71             init(st[top],st[top-1]);top--;
     72         }
     73         st[++top]=q[i];
     74     }
     75     while(top>1)init(st[top-1],st[top]),top--;
     76     dfs(1,1);
     77     printf("%lld
    ",f[1]);
     78 }
     79 void prework(int x){
     80     RG int u;
     81     dfn[x]=++DFN;
     82     for(RG int i=head[x];i;i=a[i].next){
     83         u=a[i].to;if(dep[u])continue;
     84         val[u]=min(val[x],a[i].dis);
     85         dep[u]=dep[x]+1;
     86         fa[u][0]=x;
     87         prework(u);
     88     }
     89 }
     90 void work()
     91 {
     92     RG int x,y,z;
     93     scanf("%d",&n);lim=log(n)/log(2)+1;
     94     for(int i=1;i<n;i++){
     95         scanf("%d%d%d",&x,&y,&z);
     96         addedge(x,y,z);addedge(y,x,z);
     97     }
     98     dep[1]=1;val[1]=inf;prework(1);
     99     for(RG int j=1;j<=lim;j++)
    100         for(RG int i=1;i<=n;i++)
    101             fa[i][j]=fa[fa[i][j-1]][j-1];
    102     int Q;
    103     scanf("%d",&Q);
    104     while(Q--)
    105         solve();
    106 }
    107 
    108 int main()
    109 {
    110     work();
    111     return 0;
    112 }
  • 相关阅读:
    DLinq[新特性]
    破解 iPod Touch[转]
    iPod Touch Online
    谈到Model View Presenter模式之后的随笔[讨论版]
    各家银行买"基金"如何省钱
    WF随笔系列之二 架构、编译、序列化
    JavaScript AppendChild 引发的思考
    IEquatable接口
    DLinq查询
    基金小窍门:如何判断基金的赚与赔
  • 原文地址:https://www.cnblogs.com/Yuzao/p/7354184.html
Copyright © 2020-2023  润新知