bzoj 3743 [ Coci 2015 ] Kamp —— 树形DP
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743
一开始想到了树形DP,处理一下子树中的最小值,向上的最小值,以及子树中的最长路和向上的最长路,就可以得到答案,可以DP;
然而写着写着写不下去了,不会求向上最小值和最长路;
于是看看TJ,原来要再记录一个次长路!
然而写挫了,写不下去了...
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=5e5+;
int n,m,hd[maxn],ct,fa[maxn],ans[maxn];
ll f[maxn][],g[maxn][],t[maxn],l[maxn][];
bool vis[maxn];
struct N{
int to,nxt,w;
N(int t=,int n=,int w=):to(t),nxt(n),w(w) {}
}ed[maxn<<];
void add(int x,int y,int z){ed[++ct]=N(y,hd[x],z); hd[x]=ct;}
void dfs(int x,int ft)
{
fa[x]=ft;
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==ft)continue;
dfs(u,x);
vis[x]|=vis[u];
}
}
void dp(int x)
{
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==fa[x])continue;
dp(u);
f[x][]+=(f[u][]+*vis[u]*ed[i].w);
if(l[x][]<l[u][]+vis[u]*ed[i].w)
{
l[x][]=l[x][]; t[x]=u;
l[x][]=l[u][]+vis[u]*ed[i].w;
}
else if(l[x][]<l[u][]+vis[u]*ed[i].w)l[x][]=l[u][]+vis[u]*ed[i].w;
}
f[x][]=f[x][]-l[x][];
}
void dp2(int x)
{
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==fa[x])continue;
ans[x]=min(f[x][]+g[x][],f[x][]+g[x][]);
g[u][]=g[x][]+f[x][]-f[u][];
if(u==t[x])g[u][]=min(g[x][]+f[x][]-f[u][],g[u][]-l[x][])-ed[i].w;
else g[u][]=min(g[x][]+f[x][]-f[u][],g[u][]-l[x][]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,y,z;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z); add(y,x,z);
}
for(int i=,x;i<=m;i++)
scanf("%d",&x),vis[x]=;
dfs(,); dp(); dp2();
for(int i=;i<=n;i++)printf("%lld\n",ans[i]);
return ;
}
囧
然后滚去看TJ,再次学习了一下优美的树形DP写法...
dis[x] 表示总路长,f[x][0] 表示子树中最长路,f[x][1] 表示子树中次长路,f[x][2] 表示向上最长路;
然后优美 dfs 即可...
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const maxn=5e5+,inf=0x3f3f3f3f;
int n,m,hd[maxn],ct,siz[maxn];
ll dis[maxn],f[maxn][];
bool vis[maxn];
struct N{
int to,nxt,w;
N(int t=,int n=,int w=):to(t),nxt(n),w(w) {}
}ed[maxn<<];
void add(int x,int y,int z){ed[++ct]=N(y,hd[x],z); hd[x]=ct;}
void dfs(int x,int fa)
{
// dis[x]=(vis[x]?0:-inf);
// siz[x]=(vis[x]?1:0);
siz[x]=vis[x]; dis[x]=;
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==fa)continue;
dfs(u,x); siz[x]+=siz[u];
// dis[x]+=dis[u]+ed[i].w;
dis[x]+=dis[u]+(siz[u]?ed[i].w:);
}
}
void dfs2(int x,int fa)
{
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==fa)continue;
dis[u]=dis[x];//
if(siz[u])dis[u]-=ed[i].w;
if(siz[u]<m)dis[u]+=ed[i].w;//siz[u]==0
dfs2(u,x);
}
}
void dfs3(int x,int fa)
{
f[x][]=f[x][]=(vis[x]?:(ll)-inf*inf);
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==fa)continue;
dfs3(u,x);
if(f[u][]+ed[i].w>f[x][])
{
f[x][]=f[x][];
f[x][]=f[u][]+ed[i].w;
}
else if(f[u][]+ed[i].w>f[x][])f[x][]=f[u][]+ed[i].w;
}
}
void dfs4(int x,int fa)
{
for(int i=hd[x],u;i;i=ed[i].nxt)
{
if((u=ed[i].to)==fa)continue;
if(f[u][]+ed[i].w==f[x][])f[u][]=f[x][]+ed[i].w;
else f[u][]=f[x][]+ed[i].w;
f[u][]=max(f[u][],f[x][]+ed[i].w);
dfs4(u,x);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=,x,y,z;i<n;i++)
{
scanf("%d%d%d",&x,&y,&z);
add(x,y,z); add(y,x,z);
}
for(int i=,x;i<=m;i++)scanf("%d",&x),vis[x]=;
dfs(,); dfs2(,); dfs3(,);
f[][]=(vis[]?:(ll)-inf*inf); dfs4(,);
for(int i=;i<=n;i++)printf("%lld\n",*dis[i]-max(f[i][],f[i][]));
return ;
}
bzoj 3743 [ Coci 2015 ] Kamp —— 树形DP的更多相关文章
- [BZOJ 4033] [HAOI2015] T1 【树形DP】
题目链接:BZOJ - 4033 题目分析 使用树形DP,用 f[i][j] 表示在以 i 为根的子树,有 j 个黑点的最大权值. 这个权值指的是,这个子树内部的点对间距离的贡献,以及 i 和 Fat ...
- [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)
[BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...
- [BZOJ 4455] [ZJOI 2016] 小星星 (树形dp+容斥原理+状态压缩)
[BZOJ 4455] [ZJOI 2016] 小星星 (树形dp+容斥原理+状态压缩) 题面 给出一棵树和一个图,点数均为n,问有多少种方法把树的节点标号,使得对于树上的任意两个节点u,v,若树上u ...
- bzoj 3743 [Coci2015]Kamp——树形dp+换根
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3743 树形dp+换根. “从根出发又回到根” 减去 “mx ” . 注意dfsx里真的要改那 ...
- 【BZOJ3743】[Coci2015]Kamp 树形DP
[BZOJ3743][Coci2015]Kamp Description 一颗树n个点,n-1条边,经过每条边都要花费一定的时间,任意两个点都是联通的. 有K个人(分布在K个不同的点)要集中到一个点举 ...
- 『kamp 树形dp』
kamp Description jz 市的云台山是个很美丽的景区,小 x 暑期到云台山打工,他的任务是开景区的大巴. 云台山景区有 N 个景点,这 N 个景点由 N-1 条道路连接而成,我们保证这 ...
- BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...
- BZOJ 2435 道路修建 NOI2011 树形DP
一看到这道题觉得很水,打了递归树形DP后RE了一组,后来发现必须非递归(BFS) 递归版本84分: #include<cstdio> #include<cstring> #in ...
- BZOJ 2878: [Noi2012]迷失游乐园( 树形dp )
一棵树的话直接树形dp(求出往下走和往上走的期望长度). 假如是环套树, 环上的每棵树自己做一遍树形dp, 然后暴力枚举(环上的点<=20)环上每个点跑经过环上的路径就OK了. -------- ...
随机推荐
- Ajax——php基础知识(二)
header header('content-type:text/html; charset= utf-8');//设置编码格式为:utf-8 header('location:http://www. ...
- strut2 拦截器 使用
拦截器是strut2里一个很振奋人心的应用.通过配置拦截器可以在action执行之前进行一些初始化或者是其他的操作,但是在action执行之后,返回结果就已经确定,结果是很难改变了(目前我还不知道怎么 ...
- (转)Hibernate中的多表操作
http://blog.csdn.net/yerenyuan_pku/article/details/70556208 Hibernate中的多表操作 在实际开发中,我们不可能只是简简单单地去操作单表 ...
- HDU_1063_Exponentiation_大数
Exponentiation Time Limit: 2000/500 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Tot ...
- 通过PHP怎样取到android系统下apk应用的包名,版本号等信息
公司项目关系,要求在通过PHP解析android系统应用apk包内的一切可用的信息.比如说:APK包名,版本号,版本名,安装权限等一系列关于对应包的信息.通过google查找相关的解决方案,都没有找到 ...
- vue里的tab控件
如下图,v-model绑定的值,这个值在js里一旦改变,视图就会切换到相应的tab页,这意味着一定要先给tab页内容数据赋值,再改变这个tabsIndex的值 如下图,先赋值data列表数据,在更改t ...
- day07-列表类型/元组类型/字典类型/集合类型内置方法
目录 列表类型内置方法 元组类型内置方法 字典类型内置方法 集合类型内置方法 列表类型内置方法 用来存多个元素,[]内用逗号隔开任意数据类型的元素 1. list()强制类型转换 print(list ...
- spring boot 2.0 报错:“jdbcUrl is required with driverClassName.” 解决办法!
springboot 升级到2.0之后发现配置多数据源的时候报错: "jdbcUrl is required with driverClassName."或者Cause: java ...
- 关于static关键字的思考
静态方法是否能调用非静态成员变量? static关键字具有如下特点: 一.static关键字修饰的属性/方法可以通过类名直接调用,而不必先new一个对象. 二.sta ...
- 六、Scrapy中Download Middleware的用法
本文转载自: https://scrapy-chs.readthedocs.io/zh_CN/latest/topics/downloader-middleware.html https://doc. ...