[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\n",dp(1)); 
130         for (i=1;i<=M;i++)
131         vis[a[i]]=head2[a[i]]=0;
132    }
133 }

 

posted @ 2018-02-20 11:35  Z-Y-Y-S  阅读(187)  评论(0编辑  收藏  举报