2286: [Sdoi2011]消耗战

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

Source

Stage2 day2

Solution  

  一道虚树上dp的板子题。

  设d[x]为根到x路径上的最小边,那么对于标记点,显然只能决策d[x],而非标记点可以决策min(d[x],sigma(d[y])),y为x的所有儿子。

  有两种建虚树的方法,第一种是网上的常规建法,第二种是从yyb哪儿学到的,要更简单一些。两种我都写了的。

  注意下第一种方法的insert函数里的注释,因为我们这样特殊处理了所以第一种方法不用打标记,dp时也不用限制决策;

  而第二种方法是把整棵虚树都建出来了的,因此必须打标记,而且要随时注意回溯时清空标记(不能直接memset就不用我说了吧)。

Code 1

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=,INF=0x3f3f3f3f;
inline int read(){
int x=,w=;char ch=;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<)+(x<<)+(ch^),ch=getchar();
return w?-x:x;
}
struct edge{
int v,w,last;
}e[N<<];
int tot,tail[N];
inline void add(int x,int y,int z){
e[++tot]=(edge){y,z,tail[x]};
tail[x]=tot;
}
int idx,dfn[N],dep[N],d[N],f[N][];
int dfs(int x,int pre){
dfn[x]=++idx;dep[x]=dep[pre]+;f[x][]=pre;
for(int i=;;++i)
if(f[x][i-]) f[x][i]=f[f[x][i-]][i-];
else break;
for(int p=tail[x];p;p=e[p].last){
int &v=e[p].v,&w=e[p].w;
if(v==pre) continue;
d[v]=min(d[x],w);
dfs(v,x);
}
}
int LCA(int x,int y){
if(dep[x]<dep[y]) x^=y^=x^=y;
for(int i=;i>=;--i) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
if(x==y) return x;
for(int i=;i>=;--i) if(f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
return f[x][];
}
int n,m,k,tp,st[N],a[N];
void insert(int x){
if(tp==){st[++tp]=x;return ;}
int lca=LCA(x,st[tp]);
if(lca==st[tp]){
/*任意时刻如果lca=st[tp]的话那么lca一定是标记点(lca=1除外),既然lca和x都是标记点,
那么x就不用管了呗,相当于把x的决策合并到lca上去了。*/
return ;
}
while(tp>&&dfn[st[tp-]]>=dfn[lca]) add(st[tp-],st[tp],),tp--;
if(st[tp]^lca) add(lca,st[tp],),st[tp]=lca;
st[++tp]=x;
}
LL dp(int x){
if(!tail[x]) return d[x];
LL sum=;
for(int p=tail[x];p;p=e[p].last)
sum+=dp(e[p].v);
tail[x]=;
if(x==) return sum;
else return min(sum,1ll*d[x]);
}
bool cmp(int x,int y){return dfn[x]<dfn[y];}
int main(){
n=read();
for(int i=,x,y,z;i<n;++i){
x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
d[]=INF;
dfs(,);
m=read();
tot=;memset(tail,,sizeof tail);
st[tp=]=;
while(m--){
tot=;
k=read();
for(int i=;i<=k;++i) a[i]=read();
sort(a+,a+k+,cmp);
for(int i=;i<=k;++i) insert(a[i]);
while(tp>) add(st[tp-],st[tp],),--tp;
printf("%lld\n",dp());
}
return ;
}

BZOJ2286

Code 2

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=,INF=0x3f3f3f3f;
inline int read(){
int x=,w=;char ch=;
while(!isdigit(ch)) w|=ch=='-',ch=getchar();
while(isdigit(ch)) x=(x<<)+(x<<)+(ch^),ch=getchar();
return w?-x:x;
}
struct edge{
int v,w,last;
}e[N<<];
int tot,tail[N];
inline void add(int x,int y,int z){
e[++tot]=(edge){y,z,tail[x]};
tail[x]=tot;
}
int idx,dfn[N],dep[N],d[N],low[N],f[N][];
int dfs(int x,int pre){
dfn[x]=++idx;dep[x]=dep[pre]+;f[x][]=pre;
for(int i=;;++i)
if(f[x][i-]) f[x][i]=f[f[x][i-]][i-];
else break;
for(int p=tail[x];p;p=e[p].last){
int &v=e[p].v,&w=e[p].w;
if(v==pre) continue;
d[v]=min(d[x],w);
dfs(v,x);
}
low[x]=idx;
}
int LCA(int x,int y){
if(dep[x]<dep[y]) x^=y^=x^=y;
for(int i=;i>=;--i) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
if(x==y) return x;
for(int i=;i>=;--i) if(f[x][i]^f[y][i]) x=f[x][i],y=f[y][i];
return f[x][];
}
bool tag[N];
int n,m,k,st[N<<],a[N<<];
LL dp(int x){
if(!tail[x]) {tag[x]=;return d[x];}
LL sum=;
for(int p=tail[x];p;p=e[p].last)
sum+=dp(e[p].v);
tail[x]=;
if(x==) return sum;
if(tag[x]) {tag[x]=;return d[x];}
return min(sum,1ll*d[x]);
}
bool cmp(int x,int y){return dfn[x]<dfn[y];}
int main(){
n=read();
for(int i=,x,y,z;i<n;++i){
x=read(),y=read(),z=read();
add(x,y,z),add(y,x,z);
}
d[]=INF;
dfs(,);
m=read();
tot=;memset(tail,,sizeof tail);
while(m--){
tot=;
k=read();
for(int i=;i<=k;++i) a[i]=read(),tag[a[i]]=true;
a[++k]=; //手动添加1号节点
sort(a+,a+k+,cmp);
for(int i=k;i>;--i)
a[++k]=LCA(a[i],a[i-]);
sort(a+,a+k+,cmp);
k=unique(a+,a+k+)-a-;
for(int i=,tp=;i<=k;++i){
while(tp&&low[st[tp]]<dfn[a[i]]) --tp;
if(tp) add(st[tp],a[i],);
st[++tp]=a[i];
}
printf("%lld\n",dp());
}
return ;
}

BZOJ2286

[BZOJ2286][Sdoi2011]消耗战(虚树上DP)的更多相关文章

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

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

  2. BZOJ2286: [Sdoi2011]消耗战(虚树/树形DP)

    Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 5246  Solved: 1978[Submit][Status][Discuss] Descript ...

  3. bzoj2286: [Sdoi2011]消耗战 虚树

    在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个 ...

  4. 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP

    [题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...

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

    题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...

  6. BZOJ 2286 [Sdoi2011]消耗战 ——虚树

    虚树第一题. 大概就是建一颗只与询问有关的更小的新树,然后在虚树上DP #include <map> #include <ctime> #include <cmath&g ...

  7. [BZOJ3611][Heoi2014]大工程(虚树上DP)

    3611: [Heoi2014]大工程 Time Limit: 60 Sec  Memory Limit: 512 MBSubmit: 2464  Solved: 1104[Submit][Statu ...

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

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

  9. 【BZOJ-2286】消耗战 虚树 + 树形DP

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

随机推荐

  1. Codeforces 1229A. Marcin and Training Camp

    传送门 垃圾翻译毁一生怎么办 题目看错直接 $GG$ 首先所有 $a_i$ 重复出现的人全都可以加入 考虑剩下的人发现 $a$ 必须是初始那些人的子集才能加入(证明显然),设当前考虑的人为 $x$ 则 ...

  2. spring boot 发布自动生成svn版本号

    通过Jenkins构建发布spring boot项目时,常常有需求,需要把Svn的版本号更新到项目的版本上,通过有两种解决方案: 1. 通过shell命令对配置文件中的指定字符进行替换, 如: 配置文 ...

  3. [转载]C++之using namespace std 详解与命名空间的使用

    来源:https://blog.csdn.net/Bruce_0712/article/details/72824668 所谓namespace,是指标识符的各种可见范围.C++标准程序库中的所有标识 ...

  4. Bat批处理文件入门

    这个东西吧,感觉在使用windows时作用不是很大,毕竟在windows环境下命令行确实用的比较少,但有时候也会用到,比如测试算法程序时使用批处理+文件可以省去每次手动输入.赶巧最近对批处理也比较感兴 ...

  5. JDBC2

    1.JDBC连接池 public class JdbcTemplateDemo2 { //Junit单元测试,可以让方法独立执行 //1. 获取JDBCTemplate对象 private JdbcT ...

  6. JDBC1

    ---恢复内容开始--- create table `account` ( `id` ), `name` ), `balance` ) ); insert into `account` (`id`, ...

  7. mybatis字符#与字符$的区别

    问题:使用in查询查询出一批数据,in查询的参数是字符串拼接的.调试过程中,把mybatis输出的sql复制到navicat中,在控制台将sql的参数也复制出来,替换到sql的字符 '?' 的位置,执 ...

  8. vscode常用插件列表

    vscode插件 备注 Markdown PDF 把markdown文件转换成别的文件 Markdown TOC markdown文件目录生成 PHP Debug PHP调试 PHP Intenlli ...

  9. Linux中的Mariadb数据库的主备

    对于一个mysql服务器, 一般有两个线程来负责复制和被复制.当开启复制之后. MySQL 复制的基本过程如下: 1. Slave 上面的IO线程连接上 Master,并请求从指定日志文件的指定位置( ...

  10. 第01章 部署虚拟环境安装Linux系统

    在VMware中安装RHEL系统和其它Linux系统一样,注意的是: ……前边一直操作下边的步骤后: 重启系统后将看到系统的初始化界面,单击 LICENSE INFORMATION 选项. 选中 I ...