• 【BZOJ2286】【SDOI2011】消耗战 [虚树][树形DP]


    消耗战

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

    Main idea

      给定一棵带权树,每次询问给出若干个关键节点,求出删去若干边使得关键节点无法到达根的最优方案。

    Solution

      显然想到了树形DP,但是直接做DP会TLE。

      我们又发现了其实没有必要把全部边都走完,那么只要构建一棵虚树,在虚树上跑DP即可。

      虚树构建方法: 
      1. 将关键点按照DFS序排序;
      2. 求出排序后相邻两点的LCA(可以证明就是任意两点的LCA),和关键点一起按照DFS序排序,去重后得到虚树点集;
      3. 用栈扫描一遍,维护从根到当前点的链(方法:如果栈顶是i的祖先,那么连边,加入i,否则弹栈)。

    Code

      1 #include<iostream>  
      2 #include<string>  
      3 #include<algorithm>  
      4 #include<cstdio>  
      5 #include<cstring>  
      6 #include<cstdlib>  
      7 #include<cmath>  
      8 using namespace std;  
      9    
     10 const int ONE=500001;
     11 const int INF=2147483640;
     12  
     13 int n,m,T;
     14 int x,y,z;
     15 int next1[ONE],first1[ONE],go1[ONE],w1[ONE],tot1;
     16 int next[ONE],first[ONE],go[ONE],w[ONE],tot;
     17 int size[250001],Rank[250001];
     18 int dfn[250001],cnt,num;
     19 int f[ONE][25],Dep[250001];
     20 int Output[ONE];
     21 int N;
     22 long long dp[250001];
     23 int Minedge[ONE];
     24 int vis[250001];
     25 int q[250001],top;
     26  
     27 struct power
     28 {
     29         int v;
     30         int rank;
     31 }a[ONE];
     32  
     33 int cmp(const power &a,const power &b)
     34 {
     35         return a.rank<b.rank;
     36 }
     37  
     38 int rule(const power &a,const power &b)
     39 {
     40         return (a.v==b.v && a.rank==b.rank);
     41 }
     42  
     43 int get() 
     44 {
     45         int res,Q=1;    char c;
     46         while( (c=getchar())<48 || c>57)
     47         if(c=='-')Q=-1;
     48         if(Q) res=c-48; 
     49         while((c=getchar())>=48 && c<=57) 
     50         res=res*10+c-48; 
     51         return res*Q; 
     52 }
     53  
     54 int Add(int u,int v,int z)
     55 {
     56         next1[++tot1]=first1[u];    first1[u]=tot1; go1[tot1]=v;    w1[tot1]=z;
     57         next1[++tot1]=first1[v];    first1[v]=tot1; go1[tot1]=u;    w1[tot1]=z;
     58 }
     59  
     60 int New_Add(int u,int v,int z)
     61 {
     62         next[++tot]=first[u];   first[u]=tot;   go[tot]=v;  w[tot]=z;
     63         next[++tot]=first[v];   first[v]=tot;   go[tot]=u;  w[tot]=z;
     64 }
     65  
     66 int Dfs(int u,int father)
     67 {
     68         dfn[++cnt]=u;
     69         size[u]=1;
     70         Dep[u]=Dep[father]+1;
     71         for(int i=0;i<=19;i++)
     72         {
     73             f[u][i+1]=f[f[u][i]][i];
     74         }
     75          
     76         for(int e=first1[u];e;e=next1[e])
     77         {
     78             int v=go1[e];
     79             if(v==father) continue;
     80             f[v][0]=u;
     81             Minedge[v]=min(w1[e],Minedge[u]); 
     82             Dfs(v,u);
     83             size[u]+=size[v];
     84         }
     85 }
     86  
     87 int LCA(int x,int y)
     88 {
     89         if(Dep[x]<Dep[y]) swap(x,y);
     90         for(int i=20;i>=0;i--)
     91         {
     92             if(Dep[f[x][i]]>=Dep[y]) x=f[x][i];
     93             if(x==y) return x;
     94         }
     95          
     96         for(int i=20;i>=0;i--)
     97         {
     98             if(f[x][i]!=f[y][i])
     99             {
    100                 x=f[x][i];
    101                 y=f[y][i];
    102             }
    103         }
    104          
    105         return f[x][0];
    106 }
    107  
    108 int Check(int u,int v)
    109 {
    110         if(Rank[u]<=Rank[v] && Rank[v]<=Rank[u]+size[u]-1) return 1; 
    111         return 0;
    112 }
    113  
    114 void Deal()
    115 {
    116         tot=0;
    117         for(int i=2;i<=num;i++)
    118         {
    119             int x=a[i].v;
    120             while(!Check(q[top],x)) top--;
    121             New_Add(q[top],x,Minedge[x]);
    122             q[++top]=x;
    123         }
    124 }
    125  
    126 void Tree_dp(int u,int father)
    127 {
    128         dp[u]=0;
    129         for(int e=first[u];e;e=next[e])
    130         {
    131             int v=go[e];
    132             if(v==father) continue;
    133             Tree_dp(v,u);
    134             if(vis[v]) dp[u]+=w[e];
    135             else dp[u]+=min(dp[v],(long long)w[e]);
    136         }
    137         first[u]=0;
    138 }
    139  
    140 int main()
    141 {      
    142         n=get();
    143         for(int i=1;i<n;i++)
    144         {
    145             x=get();    y=get();    z=get();
    146             Add(x,y,z);
    147         }
    148          
    149         memset(Minedge,63,sizeof(Minedge));
    150         Dfs(1,0);
    151         Minedge[1]=0;
    152         for(int i=1;i<=cnt;i++) Rank[dfn[i]]=i;
    153          
    154         T=get();
    155          
    156         while(T--)
    157         {
    158             m=get();
    159             num=0;
    160             N=m;
    161             for(int i=1;i<=m;i++)
    162             {
    163                 a[++num].v=get();
    164                 a[num].rank=Rank[a[num].v];
    165                 vis[a[num].v]=1;
    166             }
    167              
    168             sort(a+1,a+num+1,cmp);
    169             for(int i=2;i<=m;i++)
    170             {
    171                 a[++num].v=LCA(a[i].v,a[i-1].v);
    172                 a[num].rank=Rank[a[num].v];
    173             }
    174              
    175             a[++num].v=1; vis[1]=1;
    176             a[num].rank=1;
    177              
    178             sort(a+1,a+num+1,cmp);
    179             num=unique(a+1,a+num+1,rule)-1-a;
    180              
    181             top=0;  q[++top]=1;
    182             Deal();
    183             Tree_dp(1,0);
    184              
    185             printf("%lld
    ",dp[1]);
    186             for(int i=1;i<=num;i++) a[i].rank=a[i].v=vis[a[i].v]=0;
    187         }
    188          
    189 }
    View Code
  • 相关阅读:
    python 编码格式
    mysql 允许特定IP访问
    mysql “Too many connections” 解决办法
    python 微信支付
    python RSA 加密与签名
    给列表里添加字典时被最后一个覆盖
    设置MySQL允许外网访问
    Python中print/format字符串格式化实例
    ssh 将22端口换为其它 防火墙设置
    linux ubuntu nethogs安装与介绍
  • 原文地址:https://www.cnblogs.com/BearChild/p/6426691.html
Copyright © 2020-2023  润新知