哨戒炮 II

描述

你的防线成功升级,从原来的一根线变成了一棵树。这棵树有 N 个炮台,炮台与炮台之间 有 N-1 条隧道。你要选择一些炮台安装哨戒炮。在第 i 个炮台上安装哨戒炮得到的防御力为 vi。上次说过,哨戒炮离得太近会产生神奇的效果。具体来说,对于炮台 i,如果它安装了 哨戒炮且和 k 个哨戒炮用隧道直接相连,那么其防御力会变化 k*di。其中 di 为炮台 i 的抗 干扰属性值。如果为正,干扰对其有正的作用;为负,干扰对其有负的作用;为 0,则完全 不受干扰。

你的整套防线的防御力为所有哨戒炮的防御力之和。求防线的最大防御力

输入

第一行一个整数 N,表示炮台数量。

第二行 N 个整数表示 vi。

第三行 N 个整数表示 di。

接下来 N-1 行每行两个整数描述一条隧道。

输出

输出一行一个整数表示答案

样例输入

2

1 1

0 0

1 2

样例输出

2

提示

对于 20%的数据,N <= 20。

对于 40%的数据,N <= 100。

对于 70%的数据,N <= 5000。

对于 100%的数据,N <= 100000

这题杠了40min然后发现读优写挂了。

事实上状态转移方程最开始推对了啊233。。。

不难看出这是一道树形dp" role="presentation" style="position: relative;">dpdp。

我们用fi,0/1" role="presentation" style="position: relative;">fi,0/1fi,0/1表示当前在标号为i" role="presentation" style="position: relative;">ii的节点,当前节点安放哨戒炮/没有安放哨戒炮。

然后dfs" role="presentation" style="position: relative;">dfsdfs的时候用一点小技巧(瞎yy" role="presentation" style="position: relative;">yyyy的),就是每次dfs" role="presentation" style="position: relative;">dfsdfs的时候并不考虑题目中说的di" role="presentation" style="position: relative;">didi的影响,而是将这个影响转移给儿子,比如说,我们当前选了u" role="presentation" style="position: relative;">uu,然后准备从选择儿子v" role="presentation" style="position: relative;">vv的情况向当前情况转移,就可以在这一层dfs" role="presentation" style="position: relative;">dfsdfs的时候放弃计算d[p]" role="presentation" style="position: relative;">d[p]d[p]这个东西,而是在dfs" role="presentation" style="position: relative;">dfsdfs儿子v" role="presentation" style="position: relative;">vv的时候附加一个值sum" role="presentation" style="position: relative;">sumsum,在v" role="presentation" style="position: relative;">vv递归返回的时候加上这个值就行了。

但sum" role="presentation" style="position: relative;">sumsum的值如何计算呢?于是我们分情况考虑。

如果当前点u" role="presentation" style="position: relative;">uu没有被选,那么对儿子没有影响,因此无论儿子选还是不选,sum" role="presentation" style="position: relative;">sumsum值都为0" role="presentation" style="position: relative;">00。

那如果u" role="presentation" style="position: relative;">uu被选了呢?如果儿子不选,sum" role="presentation" style="position: relative;">sumsum值仍然为0" role="presentation" style="position: relative;">00,而如果儿子被选,显然总答案的值会加上d[u]+d[v]" role="presentation" style="position: relative;">d[u]+d[v]d[u]+d[v],因此sum" role="presentation" style="position: relative;">sumsum的值就等于d[u]+d[v]" role="presentation" style="position: relative;">d[u]+d[v]d[u]+d[v]。

这样一来可以轻松地写出状态转移方程了。

f[u][0]=∑max(f[v][0],f[v][1])" role="presentation" style="position: relative;">f[u][0]=∑max(f[v][0],f[v][1])f[u][0]=∑max(f[v][0],f[v][1])

f[u][1]=∑max(f[v][0],f[v][1]+d[u]+d[v])" role="presentation" style="position: relative;">f[u][1]=∑max(f[v][0],f[v][1]+d[u]+d[v])f[u][1]=∑max(f[v][0],f[v][1]+d[u]+d[v])

这样还是不够,要记得只有安放了哨戒炮的位置才能获得防御力v[i]" role="presentation" style="position: relative;">v[i]v[i],因此第二个状态转移方程事实上是错的。

应该是:f[u][1]=∑(max(f[v][0],f[v][1]+d[u]+d[v])+V[u])" role="presentation" style="position: relative;">f[u][1]=∑(max(f[v][0],f[v][1]+d[u]+d[v])+V[u])f[u][1]=∑(max(f[v][0],f[v][1]+d[u]+d[v])+V[u])

代码如下:

#include<bits/stdc++.h>
#define N 100005
#define ll long long
using namespace std;
ll dp[N][2],n,a[N],d[N],cnt=0,first[N];
struct Node{ll v,next;}e[N<<1];
inline ll read(){
    ll ans=0,w=1;
    char ch=getchar();
    while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();}
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans*w;
}
inline ll dfs(ll p,ll f,ll sum,ll fa){
    if(dp[p][f]!=-1)return dp[p][f]+sum;
    dp[p][f]=0;
    if(f==0){
        for(ll i=first[p];i;i=e[i].next){
            ll v=e[i].v;
            if(v==fa)continue;
            dp[p][f]+=max(dfs(v,0,0,p),dfs(v,1,0,p));
        }
        return dp[p][f]+sum;
    }
    dp[p][f]=d[p];
    for(ll i=first[p];i;i=e[i].next){
        ll v=e[i].v;
        if(v==fa)continue;
        dp[p][f]+=max(dfs(v,0,0,p),dfs(v,1,a[p]+a[v],p));
    }
    return dp[p][f]+sum;
}
inline void add(ll u,ll v){e[++cnt].v=v,e[cnt].next=first[u],first[u]=cnt;}
int main(){
    memset(dp,-1,sizeof(dp));
    n=read();
    for(ll i=1;i<=n;++i)d[i]=read();
    for(ll i=1;i<=n;++i)a[i]=read();
    for(ll i=1;i<n;++i){
        ll u=read(),v=read();
        add(u,v),add(v,u);
    }
    printf("%lld",max(dfs(1,0,0,1),dfs(1,1,0,1)));
    return 0;
}

2018.07.22哨戒炮 II(树形dp)的更多相关文章

  1. 2021.07.17 P3177 树上染色(树形DP)

    2021.07.17 P3177 树上染色(树形DP) [P3177 HAOI2015]树上染色 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 重点: 1.dp思想是需要什么,维护 ...

  2. [SHOI2008]仙人掌图 II——树形dp与环形处理

    题意: 给定一个仙人掌,边权为1 距离定义为两个点之间的最短路径 直径定义为距离最远的两个点的距离 求仙人掌直径 题解: 类比树形dp求直径. f[i]表示i向下最多多长 处理链的话,直接dp即可. ...

  3. 2019.02.07 bzoj4784: [Zjoi2017]仙人掌(仙人掌+树形dp)

    传送门 题意:给一个无向连通图,问给它加边形成仙人掌的方案数. 思路: 先考虑给一棵树加边形成仙人掌的方案数. 这个显然可以做树形dp. fif_ifi​表示把iii为根的子树加边形成仙人掌的方案数. ...

  4. 2018.07.22 洛谷P3047附近的牛(树形dp)

    传送门 给出一棵n" role="presentation" style="position: relative;">nn个点的树,每个点上有C ...

  5. 2018.07.22 洛谷P2986 伟大的奶牛聚集(树形dp)

    传送门 给出一棵树,树有边权和点权,若选定一个点作为中心,这棵树的代价是所有点权乘上到根的距离的和.求代价最小. 解法:一道明显的换根dp" role="presentation& ...

  6. 2018.07.22 codeforces750E(线段树维护状态转移)

    传送门 给出一个数字字串,给出若干个询问,询问在字串的一段区间保证出现2017" role="presentation" style="position: re ...

  7. 2018.07.22 洛谷P4316 绿豆蛙的归宿(概率dp)

    传送门 简单的递推. 由于是DAG" role="presentation" style="position: relative;">DAGDA ...

  8. 2018.07.22 洛谷P1967 货车运输(kruskal重构树)

    传送门 这道题以前只会树剖和最小生成树+倍增. 而现在学习了一个叫做kruskal" role="presentation" style="position: ...

  9. 2018.07.22 洛谷P3106 GPS的决斗Dueling GPS's(最短路)

    传送门 图论模拟题. 这题直接写3个(可以压成一个)spfa" role="presentation" style="position: relative;&q ...

随机推荐

  1. linux 下常用部分命令

    关机 (系统的关机.重启以及登出 ) shutdown -h now 关闭系统() init 关闭系统() shutdown -h hours:minutes & 按预定时间关闭系统 shut ...

  2. gevent 实现io自动切换,gevent.join([]), gevent.spawn, 爬虫多并发的实现

    gevent 是一个第三方库,可以很容易的实现遇到io(文件传输)操作时,程序自动跳转到下一个程序 例一: 用gevent.sleep()  来模拟io操作 import gevent def foo ...

  3. python 之九九乘法表

    for i in range(1,10): for j in range(1,i+1): print(f"{j}*{i}={i*j}",end='\t') print() 运行结果 ...

  4. Ztree学习(-)简单例子

    https://www.cnblogs.com/shinhwazt/p/5828031.html ztree包:https://pan.baidu.com/s/1vOgGm_elF-lF0VowoHw ...

  5. WP8.1 控件默认字体颜色 配置文件位置

    C:\Program Files (x86)\Windows Phone Kits\8.1\Include\abi\Xaml\Design\generic.xaml 可在App.xaml文件中over ...

  6. React 简单介绍

    React 简单介绍 作者 RK_CODER 关注 2014.12.10 17:37* 字数 2516 阅读 55715评论 6喜欢 70 why React? React是Facebook开发的一款 ...

  7. 迷你MVVM框架 avalonjs 1.3.7发布

    又到每个月的15号了,现在avalon已经固定在每个月的15号发布新版本.这次发布又带来许多新特性,让大家写码更加轻松,借助于"操作数据即操作DOM"的核心理念与双向绑定机制,现在 ...

  8. [图解tensorflow源码] 入门准备工作

     tensorflow使用了自动化构建工具bazel.脚本语言调用c或cpp的包裹工具swig.使用EIGEN作为矩阵处理工具.Nvidia-cuBLAS GPU加速计算库.结构化数据存储格式prot ...

  9. substring_index 用法

    substring_index http://blog.csdn.net/wolinxuebin/article/details/7845917 1.substring_index(str,delim ...

  10. memory management

    1. 高端内存: 内存的物理寻址范围比虚拟寻址范围大的多,有一些内存页不能永久的映射到内核地址空间. 2. 高端内存和低端内存是内核对内存物理页的划分. 参考:http://ilinuxkernel. ...