zoukankan      html  css  js  c++  java
  • [BZOJ2286][SDOI2011]消耗战(虚树DP)

    2286: [Sdoi2011]消耗战

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

    Source

    [Submit][Status][Discuss]

    首先如果一个关键点是另一个点的子孙,则这个点显然不用考虑。

    剩下的就是DP,注意到状态只会在各个关键点的LCA处考虑,于是虚树DP即可。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     4 typedef long long ll;
     5 using namespace std;
     6 
     7 const int N=500010;
     8 const ll inf=1e15;
     9 ll pre[N];
    10 int n,m,k,u,v,w,tim,top,a[N],d[N],fa[N][20],dfn[N],stk[N];
    11 
    12 bool cmp(int a,int b){ return dfn[a]<dfn[b]; }
    13 
    14 struct E{
    15     int cnt,h[N],to[N<<1],nxt[N<<1],val[N<<1];
    16     void add(int u,int v,int w=0){ to[++cnt]=v; val[cnt]=w; nxt[cnt]=h[u]; h[u]=cnt; }
    17 }G1,G2;
    18 
    19 void dfs(int x){
    20     d[x]=d[fa[x][0]]+1; dfn[x]=++tim;
    21     rep(i,1,18) fa[x][i]=fa[fa[x][i-1]][i-1];
    22     for (int i=G1.h[x],k; i; i=G1.nxt[i])
    23         if ((k=G1.to[i])!=fa[x][0])
    24             fa[k][0]=x,pre[k]=min((ll)G1.val[i],pre[x]),dfs(k);
    25 }
    26 
    27 int lca(int x,int y){
    28     if (d[x]<d[y]) swap(x,y);
    29     int t=d[x]-d[y];
    30     for (int i=18; ~i; i--) if ((t>>i)&1) x=fa[x][i];
    31     if (x==y) return x;
    32     for (int i=18; ~i; i--) if (fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
    33     return fa[x][0];
    34 }
    35 
    36 ll dp(int x){
    37     if (!G2.h[x]) return pre[x];
    38     ll res=0;
    39     for (int i=G2.h[x]; i; i=G2.nxt[i]) res+=dp(G2.to[i]);
    40     G2.h[x]=0; return min(res,pre[x]);
    41 }
    42 
    43 void build(){
    44     stk[top=1]=1; int p=1;
    45     rep(i,2,k) if (lca(a[i],a[p])!=a[p]) a[++p]=a[i];
    46     rep(i,1+(a[1]==1),p){
    47         int x=lca(a[i],stk[top]);
    48         while (top>1 && dfn[stk[top-1]]>=dfn[x])
    49             G2.add(stk[top-1],stk[top]),top--;
    50         if (x!=stk[top]) G2.add(x,stk[top]),stk[top]=x;
    51         stk[++top]=a[i];
    52     }
    53     while (top>1) G2.add(stk[top-1],stk[top]),top--;
    54 }
    55 
    56 int main(){
    57     freopen("bzoj2286.in","r",stdin);
    58     freopen("bzoj2286.out","w",stdout);
    59     scanf("%d",&n);
    60     rep(i,2,n) scanf("%d%d%d",&u,&v,&w),G1.add(u,v,w),G1.add(v,u,w);
    61     pre[1]=inf; dfs(1); scanf("%d",&m);
    62     rep(i,1,m){
    63         scanf("%d",&k); G2.cnt=0;
    64         rep(j,1,k) scanf("%d",&a[j]);
    65         sort(a+1,a+k+1,cmp); build(); printf("%lld
    ",dp(1));
    66     }
    67     return 0;
    68 }
  • 相关阅读:
    读《构建之法- 现代软件工程》一书
    自我介绍
    jQuery Validate表单验证
    oracle数据库 expdp/impdp 和 exp/imp
    Java JDK安装及环境配置
    《JavaScript》JS中的跨域问题
    Python语言基础
    .net web 应用程序C#
    C# string 常用方法
    前端获取URL和SESSON中的值
  • 原文地址:https://www.cnblogs.com/HocRiser/p/8784732.html
Copyright © 2011-2022 走看看