• [SDOI2011]消耗战


    题目描述

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

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

    输入输出格式

    输入格式:

    第一行一个整数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,表示资源丰富岛屿的编号。

    输出格式:

    输出有m行,分别代表每次任务的最小代价。

    输入输出样例

    输入样例#1: 复制
    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
    
    输出样例#1: 复制
    12
    32
    22
    

    说明

    【数据规模和约定】

    对于10%的数据,2<=n<=10,1<=m<=5,1<=ki<=n-1

    对于20%的数据,2<=n<=100,1<=m<=100,1<=ki<=min(10,n-1)

    对于40%的数据,2<=n<=1000,m>=1,sigma(ki)<=500000,1<=ki<=min(15,n-1)

    对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1

    如果是单次询问,可以$O(n)$的树dp做出来

    这题询问数很多,但$k$的和不大

    对于每次询问,我们建一棵“虚树”

    这棵虚树只包括询问点以及相应的lca

    这样在虚树上dp复杂度为$O(k)$

    总复杂度为$O(sumk)$

    树dp可以这样Min[x]表示1~x路径上最小的边

    f[x]表示1无法到达x子树中关键点的最小和

    f[x]=min(Min[x],∑f[v])

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<cstring>
      4 #include<algorithm>
      5 #include<cmath>
      6 using namespace std;
      7 typedef long long lol;
      8 const int N=1000005;
      9 struct Node
     10 {
     11     int next,to;
     12     lol dis;
     13 }edge[N],edge2[N];
     14 int head[N],head2[N],num,dep[N],a[N],s[N],cnt,dfn[N];
     15 int fa[N][25],vis[N],n,top,bin[21],ed[N],M;
     16 lol Min[N];
     17 int gi()
     18 {
     19     char ch=getchar();
     20     int x=0;
     21     while (ch<'0'||ch>'9') ch=getchar();
     22     while (ch>='0'&&ch<='9') 
     23     {
     24         x=x*10+ch-'0';
     25         ch=getchar();
     26     }
     27     return x;
     28 }
     29 bool cmp(int a,int b)
     30 {
     31     return dfn[a]<dfn[b];
     32 }
     33 void add(int u,int v,lol w)
     34 {
     35     num++;
     36     edge[num].next=head[u];
     37     head[u]=num;
     38     edge[num].to=v;
     39     edge[num].dis=w;
     40 }
     41 void dfs(int x,int pa)
     42 {int i;
     43     dep[x]=dep[pa]+1;
     44     dfn[x]=++cnt;
     45     for (i=1;bin[i]<=dep[x];i++)
     46     fa[x][i]=fa[fa[x][i-1]][i-1];
     47     for (i=head[x];i;i=edge[i].next)
     48     {
     49         int v=edge[i].to;
     50         if (v==pa) continue;
     51         Min[v]=min(Min[x],edge[i].dis);
     52         fa[v][0]=x;
     53         dfs(v,x);
     54     }
     55     ed[x]=cnt;
     56 }
     57 int lca(int x,int y)
     58 {int as,i;
     59     if (dep[x]<dep[y]) swap(x,y);
     60     for (i=20;i>=0;i--)
     61     if (bin[i]<=dep[x]-dep[y])
     62     x=fa[x][i];
     63     if (x==y) return x;
     64     for (i=20;i>=0;i--)
     65     {
     66         if (fa[x][i]!=fa[y][i])
     67         {
     68             x=fa[x][i];y=fa[y][i];
     69         }
     70     }
     71     return fa[x][0];
     72 }
     73 void add2(int u,int v)
     74 {
     75     if (u==v) return;
     76     num++;
     77     edge2[num].next=head2[u];
     78     head2[u]=num;
     79     edge2[num].to=v;
     80 }
     81 lol dp(int x)
     82 {int i;
     83   if (vis[x])
     84     return Min[x];
     85     lol tmp=0;
     86     for (i=head2[x];i;i=edge2[i].next)
     87     {
     88         int v=edge2[i].to;
     89         tmp+=dp(v);
     90     }
     91     head2[x]=0;
     92     return min(tmp,Min[x]);
     93 }
     94 int main()
     95 {int i,u,v,j,q,k;
     96  lol w;
     97  cin>>n;
     98  bin[0]=1;
     99  for (i=1;i<=20;i++)
    100  bin[i]=bin[i-1]*2;
    101   for (i=1;i<=n-1;i++)
    102    {
    103       scanf("%d%d%lld",&u,&v,&w);
    104       add(u,v,w);add(v,u,w);
    105    } 
    106    Min[1]=2e15;
    107    dfs(1,0);
    108    cin>>q;
    109    while (q--)
    110    {
    111         k=gi();
    112      M=k;
    113         num=0;
    114         for (i=1;i<=k;i++)
    115           a[i]=gi(),vis[a[i]]=1;
    116         sort(a+1,a+k+1,cmp);
    117      for (i=2;i<=k;i++)
    118        if (ed[a[i-1]]<dfn[a[i]])
    119        a[++M]=lca(a[i-1],a[i]);a[++M]=1;
    120        sort(a+1,a+M+1,cmp);
    121        M=unique(a+1,a+M+1)-a-1;
    122        s[++top]=a[1];
    123        for (i=2;i<=M;i++)
    124        {
    125            while (top&&ed[s[top]]<dfn[a[i]]) top--;
    126            add2(s[top],a[i]);
    127            s[++top]=a[i];
    128        } 
    129         printf("%lld
    ",dp(1)); 
    130         for (i=1;i<=M;i++)
    131         vis[a[i]]=head2[a[i]]=0;
    132    }
    133 }
  • 相关阅读:
    "倒计时"组件:<count-down> —— 快应用组件库H-UI
    "徽标组件"组件:<brage> —— 快应用组件库H-UI
    "头像组件"组件:<avatar> —— 快应用组件库H-UI
    "广告组件"组件:<ad> —— 快应用组件库H-UI
    "引用风格"组件:<blockquote> —— 快应用组件库H-UI
    "缩略语"组件:<abbr> —— 快应用组件库H-UI
    "地址"组件:<address> —— 快应用组件库H-UI
    "网页组件"组件:<web-view> —— 快应用组件库H-UI
    "音频播放器"组件:<audio-player> —— 快应用组件库H-UI
    "视频播放器"组件:<video-player> —— 快应用组件库H-UI
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/8454952.html
Copyright © 2020-2023  润新知