哨戒炮 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. eclipse xml 编码问题 “3 字节的 UTF-8 序列的字节 3 无效”

    原本项目没问题,git commit之后,突然报错 “3 字节的 UTF-8 序列的字节 3 无效” 尝试过改xml文件编码等,没成功.pom中设置属性,成功解决 <project.build. ...

  2. MySQLNonTransientConnectionException

    将mysql-connector-java和druid升级到最新版本: 将驱动设置为driver-class-name: com.mysql.cj.jdbc.Driver url要加上时区设置:url ...

  3. as2 针对加载进来的swf操作

    如果加载的子swf,里面的东西会随时发生变化,那么as2获取的子swf宽高也会不停在变动. 解决方法,就是在子swf里面控制设置方法,当as2需要准确获取子swf宽高时,迫使子宽高恢复到原本样子,这样 ...

  4. 使用plsql进行查询的时候出现错误:动态执行表不可访问,本会话的自动统计被终止

  5. postgresql 的操作

    基本操作: \o /tmp/11.txt ,查询结果输出到文件 \d 查询table结构 \x 切换显示方式 postgresql中可以导出某个sql的执行结果到文件中,方法是在psql中首先执行\o ...

  6. How to read very large text files fast

    Question Does anyone know the fastest way to read large text files (10Mb) into a string.Readln is ju ...

  7. 【Java】JavaIO(二)、节点流

    一.InputStream & outputStream Java字节流主要是以InputStream (输入流),outputStream(输出流)为基类,本身是抽象类不能创建实例,但是是字 ...

  8. 手动安装yii2.0-redis扩展

    1.点击下载:yii2.0-redis扩展 2.把下载的扩展文件放到vendor/yiisoft/下,命名为yii2-redis 3.修改vender/yiisoft/下的extensions.php ...

  9. 唯快不破:Web应用的13个优化步骤

    https://mp.weixin.qq.com/s?__biz=MjM5NzA1MTcyMA==&mid=2651163004&idx=2&sn=2b1be8014abf19 ...

  10. Windows phone 自定义用户控件(UserControl)——ColorPicker

    编码前 学习Windows phone自定义用户控件,在<WPF编程宝典>学习的小例子.并根据windows phone稍微的不同,做了点修改.ColorPicker(颜色拾取器):拥有三 ...