zoukankan      html  css  js  c++  java
  • 消耗战

    在一场战争中,战场由 $n$ 个岛屿和 $n-1$ 个桥梁组成,保证每两个岛屿间有且仅有一条路径可达。现在,我军已经侦查到敌军的总部在编号为 $1$ 的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望。已知在其他 $k$ 个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿。由于不同桥梁的材质和结构不同,所以炸毁不同的桥梁有不同的代价,我军希望在满足目标的同时使得总代价最小。

    侦查部门还发现,敌军有一台神秘机器。即使我军切断所有能源之后,他们也可以用那台机器。机器产生的效果不仅仅会修复所有我军炸毁的桥梁,而且会重新随机资源分布(但可以保证的是,资源不会分布到 $1$ 号岛屿上)。不过侦查部门还发现了这台机器只能够使用 $m$ 次,所以我们只需要把每次任务完成即可。

     对于100%的数据, $2 le n le 250000,m ge 1, sum{k_i} le 500000,1 le k_i le n-1 $


    Solution

    每次m个点,我们可以考虑建虚树。

    割断一个点的代价为他到虚树上父亲的路径最小值。

    然后dp就行。

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstdlib>
     4 #include<cstring>
     5 #include<algorithm>
     6 #include<cmath>
     7 #include<vector>
     8 #define ll long long
     9 #define maxn 500005
    10 using namespace std;
    11 int n,m,num,head[maxn],tot,deep[maxn],f[maxn][22]; 
    12 int a[maxn],zh[maxn],top,dy[maxn],dfn[maxn],sc,ins[maxn],cnt,flag[maxn];
    13 ll dp[maxn],g[maxn]; 
    14 vector<int>G[maxn];
    15 struct node{
    16     int v,nex;ll w;
    17 }e[maxn*2]; 
    18 void add(int t1,int t2,ll t3){
    19     e[++tot].v=t2;e[tot].w=t3;e[tot].nex=head[t1];head[t1]=tot;
    20 }
    21 void dfs(int k,int fa,ll Min){
    22     dfn[k]=++sc;dy[sc]=k;g[k]=Min;
    23     deep[k]=deep[fa]+1;f[k][0]=fa;
    24     for(int i=head[k];i;i=e[i].nex){
    25         if(e[i].v==fa)continue;
    26         dfs(e[i].v,k,min(Min,e[i].w));
    27     }
    28 }
    29 void lj(int t1,int t2){
    30     G[t1].push_back(t2);ins[++cnt]=t1;
    31 }
    32 int Lca(int u,int v){
    33     if(deep[u]<deep[v])swap(u,v);
    34     for(int x=20;x>=0;x--)if(deep[f[u][x]]>=deep[v])u=f[u][x];
    35     for(int x=20;x>=0;x--)if(f[u][x]!=f[v][x])u=f[u][x],v=f[v][x];
    36     return u==v?u:f[u][0];
    37 }
    38 void work(int k){
    39     ll sum=0;
    40     for(int i=0;i<G[k].size();i++){
    41         work(G[k][i]);
    42         sum+=dp[G[k][i]];
    43     }
    44     if(flag[k])dp[k]=g[k],flag[k]=0;
    45     else dp[k]=min(g[k],sum);
    46 }
    47 int main(){
    48     cin>>n;
    49     for(int i=1,t1,t2;i<n;i++){
    50         ll t3;
    51         scanf("%d%d%lld",&t1,&t2,&t3);
    52         add(t1,t2,t3);add(t2,t1,t3); 
    53     }
    54     dfs(1,0,1e15);
    55     for(int j=1;j<=20;j++)
    56     for(int i=1;i<=n;i++)f[i][j]=f[f[i][j-1]][j-1];
    57     cin>>m;
    58     while(m--){
    59         scanf("%d",&num);
    60         for(int i=1,t;i<=num;i++){
    61             scanf("%d",&t);a[i]=dfn[t];flag[t]=1;
    62         }
    63         sort(a+1,a+num+1);
    64         top=1;zh[top]=1;cnt=0;
    65         for(int i=1;i<=num;i++){
    66             while(1){
    67                 int l=Lca(dy[a[i]],zh[top]);
    68                 if(l==zh[top])break;
    69                 if(dfn[l]<dfn[zh[top-1]]){
    70                     lj(zh[top-1],zh[top]);top--;
    71                 }
    72                 else if(dfn[l]==dfn[zh[top-1]]){
    73                     lj(zh[top-1],zh[top]);top--;break;
    74                 }
    75                 else {
    76                     lj(l,zh[top]);zh[top]=l;break;
    77                 }
    78             }
    79             zh[++top]=dy[a[i]];
    80         }
    81         while(top>1)lj(zh[top-1],zh[top]),top--;
    82         work(1);
    83         for(int i=1;i<=cnt;i++)G[ins[i]].clear();
    84         printf("%lld
    ",dp[1]); 
    85     }
    86     return 0;
    87 }
    View Code
  • 相关阅读:
    set<char*>s
    sscanf()函数。
    C语言函数sscanf()的用法 (转载
    zjut 1179 平均数
    C++数据间隔
    C++ 保留小数
    c++ 保留小数
    c语言 保留两位小数
    c++ 如何实现保留小数并 且 不进行四舍五入
    uva-657-搜索
  • 原文地址:https://www.cnblogs.com/liankewei/p/10658495.html
Copyright © 2011-2022 走看看