题目描述

在一场战争中,战场由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])

 #include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long lol;
const int N=;
struct Node
{
int next,to;
lol dis;
}edge[N],edge2[N];
int head[N],head2[N],num,dep[N],a[N],s[N],cnt,dfn[N];
int fa[N][],vis[N],n,top,bin[],ed[N],M;
lol Min[N];
int gi()
{
char ch=getchar();
int x=;
while (ch<''||ch>'') ch=getchar();
while (ch>=''&&ch<='')
{
x=x*+ch-'';
ch=getchar();
}
return x;
}
bool cmp(int a,int b)
{
return dfn[a]<dfn[b];
}
void add(int u,int v,lol w)
{
num++;
edge[num].next=head[u];
head[u]=num;
edge[num].to=v;
edge[num].dis=w;
}
void dfs(int x,int pa)
{int i;
dep[x]=dep[pa]+;
dfn[x]=++cnt;
for (i=;bin[i]<=dep[x];i++)
fa[x][i]=fa[fa[x][i-]][i-];
for (i=head[x];i;i=edge[i].next)
{
int v=edge[i].to;
if (v==pa) continue;
Min[v]=min(Min[x],edge[i].dis);
fa[v][]=x;
dfs(v,x);
}
ed[x]=cnt;
}
int lca(int x,int y)
{int as,i;
if (dep[x]<dep[y]) swap(x,y);
for (i=;i>=;i--)
if (bin[i]<=dep[x]-dep[y])
x=fa[x][i];
if (x==y) return x;
for (i=;i>=;i--)
{
if (fa[x][i]!=fa[y][i])
{
x=fa[x][i];y=fa[y][i];
}
}
return fa[x][];
}
void add2(int u,int v)
{
if (u==v) return;
num++;
edge2[num].next=head2[u];
head2[u]=num;
edge2[num].to=v;
}
lol dp(int x)
{int i;
if (vis[x])
return Min[x];
lol tmp=;
for (i=head2[x];i;i=edge2[i].next)
{
int v=edge2[i].to;
tmp+=dp(v);
}
head2[x]=;
return min(tmp,Min[x]);
}
int main()
{int i,u,v,j,q,k;
lol w;
cin>>n;
bin[]=;
for (i=;i<=;i++)
bin[i]=bin[i-]*;
for (i=;i<=n-;i++)
{
scanf("%d%d%lld",&u,&v,&w);
add(u,v,w);add(v,u,w);
}
Min[]=2e15;
dfs(,);
cin>>q;
while (q--)
{
k=gi();
M=k;
num=;
for (i=;i<=k;i++)
a[i]=gi(),vis[a[i]]=;
sort(a+,a+k+,cmp);
for (i=;i<=k;i++)
if (ed[a[i-]]<dfn[a[i]])
a[++M]=lca(a[i-],a[i]);a[++M]=;
sort(a+,a+M+,cmp);
M=unique(a+,a+M+)-a-;
s[++top]=a[];
for (i=;i<=M;i++)
{
while (top&&ed[s[top]]<dfn[a[i]]) top--;
add2(s[top],a[i]);
s[++top]=a[i];
}
printf("%lld\n",dp());
for (i=;i<=M;i++)
vis[a[i]]=head2[a[i]]=;
}
}

[SDOI2011]消耗战的更多相关文章

  1. BZOJ 2286: [Sdoi2011]消耗战

    2286: [Sdoi2011消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2082  Solved: 736[Submit][Status] ...

  2. bzoj 2286: [Sdoi2011]消耗战 虚树+树dp

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB[Submit][Status][Discuss] Description 在一 ...

  3. bzoj千题计划254:bzoj2286: [Sdoi2011]消耗战

    http://www.lydsy.com/JudgeOnline/problem.php?id=2286 虚树上树形DP #include<cmath> #include<cstdi ...

  4. 【LG2495】[SDOI2011]消耗战

    [LG2495][SDOI2011]消耗战 题面 洛谷 题解 参考博客 题意 给你\(n\)个点的一棵树 \(m\)个询问,每个询问给出\(k\)个点 求将这\(k\)个点与\(1\)号点断掉的最小代 ...

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

    [SDOI2011]消耗战 思路: 建虚树走树形dp: 代码: #include <bits/stdc++.h> using namespace std; #define INF 1e17 ...

  6. [BZOJ2286][SDOI2011]消耗战(虚树DP)

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 4998  Solved: 1867[Submit][Statu ...

  7. BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MB Submit: 4261  Solved: 1552 [Submit][Sta ...

  8. 【BZOJ2286】[Sdoi2011]消耗战 虚树

    [BZOJ2286][Sdoi2011]消耗战 Description 在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的 ...

  9. 2286: [Sdoi2011]消耗战

    2286: [Sdoi2011]消耗战 链接 分析 虚树练习题. 构建虚树,在虚树上DP. 跟着gxb学虚-tree... 代码 #include <cstdio> #include &l ...

  10. BZOJ2286 [Sdoi2011]消耗战 和 BZOJ3611 [Heoi2014]大工程

    2286: [Sdoi2011]消耗战 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 6371  Solved: 2496[Submit][Statu ...

随机推荐

  1. Beta Scrum博客集

    听说 Beta Scrum Day 1

  2. C语言第九次作业

    一.PTA实验作业 题目1:统计大于等于平均分人数 1. 本题PTA提交列表 2.设计思路 float i为循环变量,sum=0,count=0来表示所求人数 float *p=s来储存首地址 for ...

  3. 掌握SQLServer锁的相关概念

    一.为什么要引入锁 当多个用户同时对数据库的并发操作时会带来以下数据不一致的问题: ◆丢失更新 A,B两个用户读同一数据并进行修改,其中一个用户的修改结果破坏了另一个修改的结果,比如订票系统 ◆脏读 ...

  4. exports

    暴露函数 var bar = require("./bar.js"); var msg = "你好"; var info = "呵呵"; f ...

  5. 20145237 《Java程序设计》第2周学习总结

    教材学习内容总结 本周我学习了java的基础语法.分为类型.变量与运算符,流程控制. 一.类型:1.Java可以区分为基本类型和类类型.类类型也称作参考类型.2.Java中基本类型主要是整数.字节.浮 ...

  6. 第四十八条:如果需要精确的答案,请避免使用float和double

    让一个float或者double精确的表示0.1或者10的任何负数次方值都是不可能.float和double它们执行二进制浮点运算, 它们是为了在广泛的数值范围上提供较为精确的快速近似计算而精心设计的 ...

  7. VS2013 重装 无法打开项目

    今天遇到的奇葩BUG,耗时我一下午,现在跟大家说道说道. 今天重装系统,让各种开发环境开发工具自然要重装一次,最后装完VS2013,然后刚好客户打电话要改点东西,然后我就双击项目准备打开改,然后奇葩来 ...

  8. 15-TypeScript策略模式

    在前面的简单工厂模式中,通常将每个类.接口定义到不同的文件中.在面向对象开发思想中有一个重要的原则就是封装变化点,在实际操作过程中, 通常被调用方的代码不要去更改,而是增加,这是面向对象的开闭原则.在 ...

  9. JAVA_SE基础——21.二维数组的定义

    2 二维数组的定义 基本与一维数组类似 //定义一个3行5列的二维数组 //方法1,先new对象,然后再初始化每个元素 int[][] a = new int[3][5]; a[0][0]=1; a[ ...

  10. SQL Server元数据损坏(metadata corruption)修复

    在升级一个SQL Server 2000的数据库时,遇到了一致性错误,其中有几个错误是元数据损坏(metadata corruption),特意研究了一下这个案例,因为以前也零零散散的遇到过一些一致性 ...