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. 从入门到自闭之Python名称空间

    名称空间: 内置空间:python解释器自带的一块空间 全局空间:py文件中顶格写的就是全局空间 局部空间:函数体中就是局部空间 加载顺序: 内置空间 全局空间 局部空间 # def func(): ...

  2. 手写一个python迭代器

    分析 我们都知道一个可迭代对象可以通过iter()可以返回一个迭代器. 如果想要一个对象称为可迭代对象,即可以使用for,那么必须实现__iter __()方法. 在一个类的实例对象想要变成迭代器,就 ...

  3. QVector与QMap查找效率实战(QMap快N倍,因为QVector是数组,QMap是有序二叉树,查找的时候是N和LogN的速度对比)

    因为项目使用QVector,太慢了,听说QMap比QVector查找时快,所以写一个小程序试试: 从30000个数据中找5000个 程序运行截图如下: QVector QMap 一样的数据,找一样的数 ...

  4. Java Lock的使用

    + ReentrantLock类的使用 + ReentrantReadWriteLock类的使用 1. 使用ReentrantLock类 ReentrantLock类能够实现线程之间同步互斥,并且在扩 ...

  5. (转载)sublime3安装markdown插件

    原文链接 http://www.jianshu.com/p/335b7d1be39e?utm_source=tuicool&utm_medium=referral 最近升级到了 Sublime ...

  6. 最小生成树之Prim Kruskal算法(转)

    最小生成树 首先,生成树是建立在无向图中的,对于有向图,则没有生成树的概念,所以接下来讨论的图均默认为无向图.对于一个有n个点的图,最少需要n-1条边使得这n个点联通,由这n-1条边组成的子图则称为原 ...

  7. SqlSugar

    SqlSugar 官网 SqlSugar 源码 SqlSugar NuGet

  8. 第二章 单表查询 T-SQL语言基础(1)

    单表查询(1) 本章:逻辑查询处理,特定的SELECT查询生成正确的结果集而要经历的一系列逻辑阶段;单表查询的其他方面,包括:运算符,空值(NULL),字符的处理和临时数据,分级(ranking),C ...

  9. golang(5):struct & 链表 & 二叉树 & 接口

    struct : 结构体 // 1. 用来自定义复杂数据结构 // 2. struct里面可以包含多个字段(属性) // 3. struct类型可以定义方法,注意和函数的区分 // 4. struct ...

  10. Git复习(五)之多人协作、git push失败、git pull失败

    多人协作 多人协作时,大家都会往master和dev分支上推送各自的修改. 现在,模拟一个你的小伙伴,可以在另一台电脑(注意要把SSH Key添加到GitHub)或者同一台电脑的另一个目录下克隆: $ ...