题意:

有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. Codeforces Round #192 (Div. 2) (330B) B.Road Construction

    题意: 要在N个城市之间修建道路,使得任意两个城市都可以到达,而且不超过两条路,还有,有些城市之间是不能修建道路的. 思路: 要将N个城市全部相连,刚开始以为是最小生成树的问题,其实就是一道简单的题目 ...

  2. openGL基本概念

    OpenGL自身是一个巨大的状态机(State Machine):一系列的变量描述OpenGL此刻应当如何运行.OpenGL的状态通常被称为OpenGL上下文(Context).我们通常使用如下途径去 ...

  3. AndroidSDK的目录详解

    Tools 目录工具(必须的工具) Android SDK Tools(必须,只需下载一个版本,一般选最新版本):基础工具包,版本号带rc字样的是预览版. Android SDK Platform-t ...

  4. js 双向绑定数据

    let aaa = []; let bbb = [1,2,3]; let ccc = [0,9,8]; aaa = bbb; //此时aaa与bbb被绑定(aaa指向bbb的指向) ,若使用push则 ...

  5. 【Java例题】5.3 字符统计

    3.分别统计一个字符串中大写字母.小写字母.数字. 汉字以及其它字符的个数. package chapter5; import java.util.Scanner; public class demo ...

  6. Hadoop学习(9)-spark的安装与简单使用

    spark和mapreduce差不多,都是一种计算引擎,spark相对于MapReduce来说,他的区别是,MapReduce会把计算结果放 在磁盘,spark把计算结果既放在磁盘中有放在内存中,ma ...

  7. Vue系列:.sync 修饰符的作用及使用范例

    作用:对传递给子组件的 prop 数据进行“双向绑定”.(正常情况下,prop 的数据都是单向数据流) 代码参考如下: 父组件部分 子组件部分

  8. indexedDB添加,删除,获取,修改

    [toc] 在chrome(版本 70.0.3538.110)测试正常 编写涉及:css, html, js 在线演示codepen html代码 <h1>indexedDB</h1 ...

  9. Golang 解决 Iris 被墙的依赖包

    使用 Golang 的 Iris web 框架时,用 go get github.com/kataras/iris 命令久久无法下载,最后还报一堆错误. 使用  GOPROXY 可解决问题,也可参考如 ...

  10. 重读《学习JavaScript数据结构与算法-第三版》- 第4章 栈

    定场诗 金山竹影几千秋,云索高飞水自流: 万里长江飘玉带,一轮银月滚金球. 远自湖北三千里,近到江南十六州: 美景一时观不透,天缘有分画中游. 前言 本章是重读<学习JavaScript数据结构 ...