[BZOJ2286][Sdoi2011]消耗战(虚树上DP)
2286: [Sdoi2011]消耗战
Time Limit: 20 Sec Memory Limit: 512 MB
Submit: 6457 Solved: 2533
[Submit][Status][Discuss]
Description
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
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
32
22
HINT
对于100%的数据,2<=n<=250000,m>=1,sigma(ki)<=500000,1<=ki<=n-1
Source
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)的更多相关文章
- [BZOJ2286][SDOI2011]消耗战(虚树DP)
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4998 Solved: 1867[Submit][Statu ...
- BZOJ2286: [Sdoi2011]消耗战(虚树/树形DP)
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 5246 Solved: 1978[Submit][Status][Discuss] Descript ...
- bzoj2286: [Sdoi2011]消耗战 虚树
在一场战争中,战场由n个岛屿和n-1个桥梁组成,保证每两个岛屿间有且仅有一条路径可达.现在,我军已经侦查到敌军的总部在编号为1的岛屿,而且他们已经没有足够多的能源维系战斗,我军胜利在望.已知在其他k个 ...
- 【BZOJ】2286: [Sdoi2011]消耗战 虚树+DP
[题意]给定n个点的带边权树,每次询问给定ki个特殊点,求隔离点1和特殊点的最小代价.n<=250000,Σki<=500000. [算法]虚树+DP [题解]考虑普通树上的dp,设f[x ...
- bzoj 2286 [Sdoi2011]消耗战 虚树+dp
题目大意:多次给出关键点,求切断边使所有关键点与1断开的最小费用 分析:每次造出虚树,dp[i]表示将i和i子树与父亲断开费用 对于父亲x,儿子y ①y为关键点:\(dp[x]\)+=\(dismn( ...
- BZOJ 2286 [Sdoi2011]消耗战 ——虚树
虚树第一题. 大概就是建一颗只与询问有关的更小的新树,然后在虚树上DP #include <map> #include <ctime> #include <cmath&g ...
- [BZOJ3611][Heoi2014]大工程(虚树上DP)
3611: [Heoi2014]大工程 Time Limit: 60 Sec Memory Limit: 512 MBSubmit: 2464 Solved: 1104[Submit][Statu ...
- BZOJ2286 [Sdoi2011]消耗战 【虚树 + 树形Dp】
2286: [Sdoi2011]消耗战 Time Limit: 20 Sec Memory Limit: 512 MB Submit: 4261 Solved: 1552 [Submit][Sta ...
- 【BZOJ-2286】消耗战 虚树 + 树形DP
2286: [Sdoi2011消耗战 Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 2120 Solved: 752[Submit][Status] ...
随机推荐
- 矩阵快速幂(Matrix_Fast_Power)
一.基础知识(1)矩阵乘法 https://blog.csdn.net/weixin_43272781/article/details/82899737 简单的说矩阵就是二维数组,数存在里面,矩阵乘法 ...
- Codeforces 1201E2. Knightmare (hard)
传送门 看到棋盘先黑白染色冷静一下 然后分析发现,如果初始时两只马在同色的格子,那么一定是后手吃先手 反之一定是先手吃后手 所以分类讨论一下,如果初始在同色的格子,并且后手到达终点的步数更少,那么后手 ...
- shell脚本获取的参数
$# 是传给脚本的参数个数 $0 是脚本本身的名字 $1 是传递给该shell脚本的第一个参数 $2 是传递给该shell脚本的第二个参数 $@ 是传给脚本的所有参数的列表
- intelij IDEA设置goole code style风格
1.安装google-java-format 插件 file ->Setings... ->pligins 输入上诉插件安装 2.下载IntelliJ Java Goog ...
- the Percentage Layout of Android (安卓的百分比布局)
不用wrap_content.match_parent来指定 控件的大小, 1.在app/bulid.gradle文件的dependencies中添加 compile 'com.android.sup ...
- Eclipse安装Hadoop插件配置Hadoop开发环境
一.编译Hadoop插件 首先需要编译Hadoop 插件:hadoop-eclipse-plugin-2.6.0.jar,然后才可以安装使用. 第三方的编译教程:https://github.com/ ...
- 07 Nginx负载均衡
1.负载均衡的实现. 1.准备三台虚拟机,比如 192.168.119.146 提供资源 192.168.119.147 提供nginx的负载均衡 192.168.119.148 提供资源 2.分别配 ...
- 上传模板到SAP资源库
事物代码:SMW0 -WEB资源库 如果创建后上载本地模板报错,说明没有维护文件类型,需要在导航栏的设置里维护MIME类型添加新的文件后缀名 维护好后再上载模板 ABAP下载模板:以下FORM可以参考 ...
- Linux Exploit系列之六 绕过ASLR - 第一部分
绕过ASLR - 第一部分 什么是 ASLR? 地址空间布局随机化(ASLR)是随机化的利用缓解技术: 堆栈地址 堆地址 共享库地址 一旦上述地址被随机化,特别是当共享库地址被随机化时,我们采取的绕过 ...
- 深入理解python元类
类也是对象 在理解元类之前,你需要先掌握Python中的类.Python 中的类概念借鉴 Smalltalk,这显得有些奇特.在大多数编程语言中,类就是一组用来描述如何生成一个对象的代码段.当然在 P ...