题意:

有n种商品,每种商品有一个价格 p[i] 。

每种商品都有2种打折方式:

1. 给你优惠 d[i] 元。

2. 免费送你第 f[i] 种饮料。

现在求每种饮料至少一瓶的最小花费。

dp[i][0] 表示 i 的子树内所有的饮料都至少买了一瓶。

dp[i][1] 表示 i 的子树内所有的饮料都至少买了一瓶 且 第i种饮料是使用第2种方式购买的。

我们考虑树的转移方式。

sum[i] 表示  dp[son[i]][0] 的和

dp[i][1] = sum[i] + p[i]

dp[i][0] = min(p[i]-d[i]+sum[i], sum[i] - dp[son[i][0] + dp[son[i][1] )

然后我们可以先把环都抠出来, 然后将环上的边都标记一下,

然后先把环的子树都转移到环上来, 最后再处理环的问题。

假设一个环为 a -> b -> c ->  d  -> a ,mn 为这个环的最小花费。

我们断开a -> b 这条边,并且 b 不是 通过 a 送来的。

G[0][0] = dp[b][0] G[0][1] = dp[b][1]

路上转移的状态为 G[1][1] = dp[c][1] + G[0][0];

G[1][0] = min(G[0][1]+sum[c], dp[c][0] + G[0][0])

这样一直转移到G[3][0]

因为我们规定b 不是 通过 a 送来的。 mn = min(mn, G[3][0])

然后我们假设 b 是通过 a 送过来的

G[0][0] = sum[b]    G[0][1] = dp[b][1]

然后通过上面的转移方程转移到G[3][1]。

因为b是a送的 那么 a 必须要按方式1购买 所以 mn = min(mn, G[3][1])

最后将 mn 加入答案中。

然后 跑完所有环之后 就能得到答案了。

 #include<bits/stdc++.h>
using namespace std;
#define Fopen freopen("_in.txt","r",stdin); freopen("_out.txt","w",stdout);
#define LL long long
#define ULL unsigned LL
#define fi first
#define se second
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define max3(a,b,c) max(a,max(b,c))
#define min3(a,b,c) min(a,min(b,c))
typedef pair<int,int> pll;
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = (int)1e9+;
const int N = 1e5 + ;
int p[N], d[N], f[N];
int head[N], to[N], nt[N];
int vis[N];
int cntCir = , tot = , top, n;
int sta[N];
vector<int> cir[N];
int vvis[N];
LL dp[N][];
LL sum[N];
LL G[N][];
void add(int u, int v){
to[tot] = v;
nt[tot] = head[u];
head[u] = tot++;
}
void getCir(int u){
if(vis[u] == ) return ;
if(vis[u] == -){
cntCir++;
for(int i = top; i >= ; i--){
cir[cntCir].pb(sta[i]);
vvis[sta[i]] = ;
if(sta[i] == u) break;
}
return;
}
vis[u] = -;
sta[++top] = u;
getCir(f[u]);
top--;
vis[u] = ;
}
void dfs(int u){
for(int i = head[u]; ~i; i = nt[i]){
if(vvis[to[i]]) continue;
dfs(to[i]);
sum[u] += dp[to[i]][];
}
dp[u][] = sum[u] + p[u];
dp[u][] = sum[u] + p[u] - d[u];
for(int i = head[u]; ~i; i = nt[i]){
if(vvis[to[i]]) continue;
dp[u][] = min(dp[u][], sum[u] - dp[to[i]][] + dp[to[i]][]);
}
}
int main(){
memset(head, -, sizeof(head));
scanf("%d", &n);
for(int i = ; i <= n; i++) scanf("%d", &p[i]);
for(int i = ; i <= n; i++) scanf("%d", &d[i]);
for(int i = ; i <= n; i++) {
scanf("%d", &f[i]);
add(f[i], i);
}
for(int i = ; i <= n; i++){
if(!vis[i]){
top = ;
getCir(i);
}
}
LL ans = ;
for(int i = ; i <= cntCir; i++){
reverse(cir[i].begin(), cir[i].end());
for(int j = ; j < cir[i].size(); j++){
dfs(cir[i][j]);
}
LL mn = INF;
G[][] = dp[cir[i][]][];
G[][] = dp[cir[i][]][];
for(int j = ; j < cir[i].size(); j++){
G[j][] = G[j-][] + dp[cir[i][j]][];
G[j][] = min(G[j-][]+sum[cir[i][j]], dp[cir[i][j]][]+G[j-][]);
}
mn = min(mn, G[cir[i].size()-][]);
G[][] = sum[cir[i][]];
G[][] = dp[cir[i][]][];
for(int j = ; j < cir[i].size(); j++){
G[j][] = G[j-][] + dp[cir[i][j]][];
G[j][] = min(G[j-][]+sum[cir[i][j]], dp[cir[i][j]][]+G[j-][]);
}
mn = min(mn, G[cir[i].size()-][]);
ans += mn;
}
printf("%lld\n", ans);
return ;
}

牛客多校第二场B discount 基环内向树的更多相关文章

  1. 2019牛客多校第二场E MAZE(线段树 + 矩阵)题解

    题意: n * m的矩阵,为0表示可以走,1不可以走.规定每走一步只能向下.向左.向右走.现给定两种操作: 一.1 x y表示翻转坐标(x,y)的0.1. 二.2 x y表示从(1,x)走到(n,y) ...

  2. 2019牛客多校第二场 A Eddy Walker(概率推公式)

    2019牛客多校第二场 A Eddy Walker(概率推公式) 传送门:https://ac.nowcoder.com/acm/contest/882/A 题意: 给你一个长度为n的环,标号从0~n ...

  3. 牛客多校第二场A run(基础DP)

    链接:https://www.nowcoder.com/acm/contest/140/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 131072K,其他语言2621 ...

  4. run (牛客多校第二场)计数DP

    链接:https://www.nowcoder.com/acm/contest/140/A来源:牛客网 题目描述 White Cloud is exercising in the playground ...

  5. 2019牛客多校第二场H-Second Large Rectangle

    Second Large Rectangle 题目传送门 解题思路 先求出每个点上的高,再利用单调栈分别求出每个点左右两边第一个高小于自己的位置,从而而得出最后一个大于等于自己的位置,进而求出自己的位 ...

  6. 2019年牛客多校第二场 H题Second Large Rectangle

    题目链接 传送门 题意 求在\(n\times m\)的\(01\)子矩阵中找出面积第二大的内部全是\(1\)的子矩阵的面积大小. 思路 处理出每个位置往左连续有多少个\(1\),然后对每一列跑单调栈 ...

  7. [2019牛客多校第二场][G. Polygons]

    题目链接:https://ac.nowcoder.com/acm/contest/882/G 题目大意:有\(n\)条直线将平面分成若干个区域,要求处理\(m\)次询问:求第\(q\)大的区域面积.保 ...

  8. 第二大矩阵面积--(stack)牛客多校第二场-- Second Large Rectangle

    题意: 给你一幅图,问你第二大矩形面积是多少. 思路: 直接一行行跑stack求最大矩阵面积的经典算法,不断更新第二大矩形面积,注意第二大矩形可能在第一大矩形里面. #define IOS ios_b ...

  9. 2019 牛客多校第二场 H Second Large Rectangle

    题目链接:https://ac.nowcoder.com/acm/contest/882/H 题目大意 给定一个 n * m 的 01 矩阵,求其中第二大的子矩阵,子矩阵元素必须全部为 1.输出其大小 ...

随机推荐

  1. 深入理解Java中的AQS

    AQS概述 ​ AbstractQueuedSynchronizer抽象队列同步器简称AQS,它是实现同步器的基础组件,juc下面Lock的实现以及一些并发工具类就是通过AQS来实现的,这里我们通过A ...

  2. Python3数据驱动ddt

    对于同一个方法执行大量数据的程序时,我们可以采用ddt数据驱动的方式,来对数据规范化整理及输出 一.需要使用python的ddt库,ddt,data,unpack方法 1.仅使用ddt和data,代码 ...

  3. 【iOS】沙盒目录

    有关沙盒目录参考: http://blog.csdn.net/totogo2010/article/details/7669837 获取沙盒路径,参考代码: NSArray *paths = NSSe ...

  4. Hadoop 系列(三)—— 分布式计算框架 MapReduce

    一.MapReduce概述 Hadoop MapReduce 是一个分布式计算框架,用于编写批处理应用程序.编写好的程序可以提交到 Hadoop 集群上用于并行处理大规模的数据集. MapReduce ...

  5. JAVA基础知识(三):input.nextLine() 和input.next()

    next()方法在读取内容时,会过滤掉有效字符前面的无效字符,对输入有效字符之前遇到的空格键.Tab键或Enter键等结束符,next()方法会自动将其过滤掉:只有在读取到有效字符之后,next()方 ...

  6. hadoop学习(五)----HDFS的java操作

    前面我们基本学习了HDFS的原理,hadoop环境的搭建,下面开始正式的实践,语言以java为主.这一节来看一下HDFS的java操作. 1 环境准备 上一篇说了windows下搭建hadoop环境, ...

  7. [原创实践]IBM thinkpad T61制作和使用recovery光盘进行出厂系统恢复

    制作系统恢复盘 之前制作了系统恢复光盘,包含Product recovery 光盘1和光盘2,rescure and recovery光盘. 联想笔记本XP系统有一个硬盘分区是用来做恢复的,双击硬盘即 ...

  8. Git简易使用教程

    1.Git 安装 2.设置git登录信息 3.git操作命令 4.提交代码的过程中几个命令的顺序 5.git 学习资料. 1.Git 安装 Git 下载地址:https://git-scm.com/d ...

  9. 监控JVM

    WAS配置visualVM 在was控制台:找到应用程序服务器--java和进程管理--进程定义--JAVA虚拟机/通用JVM 参数 ,对应英文Application servers > ser ...

  10. DNS解析综合学习案例

    DNS解析综合学习案例 #图右侧为做题前环境配置 #命令为红色 #命令加载内容为绿色 #vi编辑内容为蓝色 1.用户需把/dev/myvg/mylv逻辑卷以支持磁盘配额的方式挂载到网页目录下 [roo ...