题意:

有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. 【Vue前端】Vue前端注册业务实现!!!【代码】

    用户注册前端逻辑 1. Vue绑定注册界面准备 1.导入Vue.js库和ajax请求的库 <script type="text/javascript" src="{ ...

  2. C#实现Hash应用全解

    1.引言 HASH是根据文件内容的数据通过逻辑运算得到的数值, 不同的文件(即使是相同的文件名)得到的HASH值是不同的. 通过一定的哈希算法(典型的有MD5,SHA-1等),将一段较长的数据映射为较 ...

  3. .net core web api部署到Linux系统CentOS 7

    一.创建一个.net core web api 的Demo 完成后的项目结构如图 修改下监听端口 发布代码 二.发布到CentOS 7上并运行 下一步需要一定的虚拟机知识了,我这里使用了windows ...

  4. 使用top查看进程和系统负载信息

    引言      使用top命令,可以查看正在运行的进程和系统负载信息,包括cpu负载.内存使用.各个进程所占系统资源等,top可以以一定频率更新这些统计信息.下面我们来学习top命令的具体使用方法. ...

  5. 通过注解实现通用导出Excel

    Javaweb开发中数据的导入导出很常见,每次我们都需要写很多代码,所以我就在想能不能写一些通用的方法,之前已经在网上 整理过一些通用的方法,最近在网上看到一位牛人封装的更加简介,自己拿过来整理了一下 ...

  6. 从头开始制作OJ-在线IDE的搭建

    大家好,我是Fred913. 之前,我看过各种OJ(OpenJudge) 但是,还是没有自己做的好. 所以,我就来写了这篇教程. 环境 这次,我打算使用这些:PHP 5.6 Nginx/Apache ...

  7. spring cloud 断路器 Hystrix

    一.微服务架构中使用断路器的原因 二.代码实现 1.在Ribbon中使用短路器 1.1.引入依赖 <dependency> <groupId>org.springframewo ...

  8. 构建企业级数据湖?Azure Data Lake Storage Gen2不容错过(上)

    背景 相较传统的重量级OLAP数据仓库,“数据湖”以其数据体量大.综合成本低.支持非结构化数据.查询灵活多变等特点,受到越来越多企业的青睐,逐渐成为了现代数据平台的核心和架构范式. 数据湖的核心功能, ...

  9. canvas 鼠标位置缩放图形

    最近再做 webcad , 需要在 canvas  上对图形进行缩放,主要分为以下几个步骤: 1.找到当前光标所在位置,确定其在相对 canvas 坐标系的坐标 绑定鼠标滚轮事件,假定每次缩放比例 0 ...

  10. (三)(1)线程间通信---wait和notify的使用

    这篇博客记录线程间通信相关api使用以及理解. 首先第一点,我之前的博客里的线程之间也是通信的,但是他们的通信是建立在访问的是同一个变量上的,相当于是变量.数据层面上的通信,而下面要讲的是线程层面上的 ...