[Sdoi2011]消耗战

2286: [Sdoi2011]消耗战

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

虚树DP。

pre.cjk { font-family: "Droid Sans Fallback", monospace }
p { margin-bottom: 0.25cm; line-height: 120% }
a:link { }

建虚树的时候,若在某个点上面有询问点,则这个点就没有用,所以这个点就不用加进虚树了。所以在DP的时候就不用开个bj数组记录哪些点是询问点,因为若一个点是询问点,那么这个点肯定是叶节点,所以就不用开数组记录了。
  1 #include<set>
  2 #include<map>
  3 #include<queue>
  4 #include<stack>
  5 #include<ctime>
  6 #include<cmath>
  7 #include<string>
  8 #include<vector>
  9 #include<cstdio>
 10 #include<cstdlib>
 11 #include<cstring>
 12 #include<iostream>
 13 #include<algorithm>
 14 #define maxn 250010
 15 #define inf 1999999999999999999ll
 16 #define LL long long
 17 using namespace std;
 18 struct data{
 19   int nex,to;
 20   LL w;
 21 }e[maxn*2],g[maxn*2];
 22 int head[maxn],edge=0,head1[maxn],edge1=0;
 23 int dfn[maxn],a[maxn],deep[maxn],size[maxn];
 24 int f[maxn][20],Stack[maxn];
 25 LL dis[maxn],dp[maxn];
 26 bool bj[maxn];
 27 inline void add(int from,int to,int w){
 28   if(from==to) return;
 29   e[++edge].nex=head[from];
 30   e[edge].to=to;
 31   e[edge].w=w;
 32   head[from]=edge;
 33 }
 34 inline void link(int from,int to){
 35   if(from==to) return;
 36   g[++edge1].nex=head1[from];
 37   g[edge1].to=to;
 38   head1[from]=edge1;
 39 }
 40 int de=0;
 41 void dfs(int x,int fa){
 42   ++de;
 43   dfn[x]=de;
 44   size[x]++;
 45   for(int i=head[x];i;i=e[i].nex){
 46     int u=e[i].to;
 47     if(u==fa) continue;
 48     f[u][0]=x;
 49     deep[u]=deep[x]+1;
 50     dis[u]=min(dis[x],e[i].w);
 51     dfs(u,x);
 52     size[x]+=size[u];
 53   }
 54 }
 55 void DP(int x,int fa){
 56   LL ans=0;
 57   dp[x]=dis[x];
 58   for(int i=head1[x];i;i=g[i].nex){
 59     int u=g[i].to;
 60     if(u==fa) continue;
 61     DP(u,x);
 62     ans+=dp[u];
 63   }
 64   head1[x]=0;
 65   if(!ans) dp[x]=dis[x];
 66   else if(ans<dp[x]) dp[x]=ans;
 67 }
 68 inline int lca(int x,int y){
 69   if(deep[x]<deep[y]) swap(x,y);
 70   for(int i=18;i>=0;i--)
 71     if(deep[f[x][i]]>=deep[y]) x=f[x][i];
 72   if(x==y) return x;
 73   for(int i=18;i>=0;i--)
 74     if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
 75   return f[x][0];
 76 }
 77 bool cmp(int a,int b){
 78   return dfn[a]<dfn[b];
 79 }
 80 inline void build(){
 81   int tot=0,m,top=0,LCA;scanf("%d",&m);
 82   for(int i=1;i<=m;i++) scanf("%d",&a[i]);
 83   sort(a+1,a+m+1,cmp);
 84   a[++tot]=a[1];
 85   for(int i=2;i<=m;i++) if(lca(a[i],a[tot])!=a[tot]) a[++tot]=a[i];
 86   Stack[++top]=1;
 87   for(int i=1;i<=tot;i++){
 88     if(top==0){Stack[++top]=a[i];continue;}
 89     LCA=lca(Stack[top],a[i]);
 90     while(1){
 91       if(deep[Stack[top-1]]<=deep[LCA]){
 92     link(Stack[top],LCA),link(LCA,Stack[top]);
 93     top--;
 94     if(Stack[top]!=LCA) Stack[++top]=LCA;
 95     break;
 96       }
 97       link(Stack[top],Stack[top-1]),link(Stack[top-1],Stack[top]);
 98       top--;
 99     }
100     if(Stack[top]!=a[i])
101       Stack[++top]=a[i];
102   }
103   while(top>1)link(Stack[top],Stack[top-1]),link(Stack[top-1],Stack[top]),top--;
104   top--;
105   DP(1,0);
106   printf("%lld\n",dp[1]);
107   edge1=0;
108 }
109 int main()
110 {
111   freopen("!.in","r",stdin);
112   freopen("!.out","w",stdout);
113   int n,x,y,z,qes;
114   scanf("%d",&n);
115   for(int i=1;i<n;i++)
116     scanf("%d%d%d",&x,&y,&z),add(x,y,z),add(y,x,z);
117   deep[1]=1,dis[1]=inf;
118   dfs(1,0);
119   for(int i=1;i<=18;i++)
120     for(int j=1;j<=n;j++)
121       f[j][i]=f[f[j][i-1]][i-1];
122   scanf("%d",&qes);
123   for(int i=1;i<=qes;i++)
124     build();
125   return 0;
126 }

 
时间: 2024-10-10 09:49:24

[Sdoi2011]消耗战的相关文章

bzoj 2286 [Sdoi2011]消耗战(虚树+树上DP)

2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 1276  Solved: 445[Submit][Status][Discuss] Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸

AC日记——[SDOI2011]消耗战 洛谷 P2495

[SDOI2011]消耗战 思路: 建虚树走树形dp: 代码: #include <bits/stdc++.h> using namespace std; #define INF 1e17 #define maxn 250005 #define ll long long #define maxm (maxn<<1) struct LandType { ll id,key; bool operator<(const LandType pos)const { return key

luogu P2495 [SDOI2011]消耗战

二次联通门 : luogu P2495 [SDOI2011]消耗战 /* luogu P2495 [SDOI2011]消耗战 虚树+树形dp 首先对原图构建出虚树 在建图的时候处理出最小值 转移即可 小技巧 在dp的过程中可以顺便把边表清空 将边结构体封装可方便的建多张图 */ #include <cstdio> #include <iostream> #include <cstring> #include <algorithm> #define INF 1

【BZOJ2286】[Sdoi2011]消耗战 虚树

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

&lt;虚树+树型DP&gt; SDOI2011消耗战

<虚树+树型DP> SDOI2011消耗战 #include <iostream> #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> using namespace std; typedef long long LL; const int MAXN = 25e4 + 10; inline LL in() { LL x = 0, flag

bzoj 2286: [Sdoi2011消耗战

1 #include<cstdio> 2 #include<iostream> 3 #define M 1000009 4 #define N 250009 5 #define ll long long 6 #define inf 1000000000000000000LL 7 #include<algorithm> 8 using namespace std; 9 int n,head[N],next[M],u[M],cnt,fa[N][22],deep[N],m,h

Bzoj2286 [Sdoi2011消耗战

Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 3003  Solved: 1081 Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个岛屿上有丰富能源,为了防止敌军获取能源,我军的任务是炸毁一些桥梁,使得敌军不能到达任何能源丰富的岛屿.由于不同桥梁的材质和结构不同,所以炸毁不

BZOJ2286 [Sdoi2011]消耗战

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

[bzoj2286][Sdoi2011]消耗战(虚树上的DP)

题目:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2286 分析:对于普通的树形dp:f[x]=min(∑f[son],m[x]),其中f[x]表示以x为根的子树所有关键点全部断开所需要的最少代价,m[x]表示从根节点到x节点的路径上最短的边 这样的话复杂度是n*m的,明显TLE 注意到数据范围里提到,所有询问的总的点数<=n,也就是说询问虽然很多,但每次询问的点的个数不多,也就是说如果对所有的点做树形dp就很不值得 于是我们就要取出那