Description
有 n n 种饮料,第种饮料价格为 p[i] p [ i ] ,当买第 i i 种饮料时有两种优惠:
1.直接优惠元,也就是说只需要花费 p[i]−d[i] p [ i ] − d [ i ] 买第 i i 种饮料
2.免费得到第种饮料
问这 n n 种饮料每种至少有一个所需的最少花费
Input
第一行一整数表示饮料种类,之后输入 n n 个整数表示每种饮料的价格,之后输入 n n 个整数,最后输入 n n 个整数
(1≤n≤105,0≤d[i]≤p[i]≤109,1≤f[i]≤n) ( 1 ≤ n ≤ 10 5 , 0 ≤ d [ i ] ≤ p [ i ] ≤ 10 9 , 1 ≤ f [ i ] ≤ n )
Output
输出最小花费
Sample Input
3
10 3 5
5 0 5
1 3 2
Sample Output
8
Solution
以赠送关系反向建图构成若干基环,首先考虑树上问题,则第二种优惠方式为购买某个儿子节点可以赠送该点,以 g[u][0] g [ u ] [ 0 ] 表示以 u u 为根的子树中每点都至少买一次的最少代价,以表示以 u u 为根的子树中每点都至少买一次,且以第二种优惠方式购买点的最少代价(即可以赠送 u u 的父亲节点),那么有转移
g[u][0]=min(p[u]−d[u]+∑v∈son(u)g[v][0],minw∈son(u)g[w][1]+∑v∈son(u),v≠wg[v][0]) g [ u ] [ 0 ] = min ( p [ u ] − d [ u ] + ∑ v ∈ s o n ( u ) g [ v ] [ 0 ] , min w ∈ s o n ( u ) g [ w ] [ 1 ] + ∑ v ∈ s o n ( u ) , v ≠ w g [ v ] [ 0 ] )
其中 g[u][0] g [ u ] [ 0 ] 的转移即为要么用第一种优惠购买 u u ,要么是通过购买 u u 的某个儿子赠送的
令 sum[u]=∑v∈son(u)g[v][0] s u m [ u ] = ∑ v ∈ s o n ( u ) g [ v ] [ 0 ] ,则上述转移可以写成
g[u][1]=p[u]+sum[u] g [ u ] [ 1 ] = p [ u ] + s u m [ u ]
g[u][0]=min(p[u]−d[u]+sum[u],minw∈son(u)(g[w][1]−g[w][0])+sum[u]) g [ u ] [ 0 ] = min ( p [ u ] − d [ u ] + s u m [ u ] , min w ∈ s o n ( u ) ( g [ w ] [ 1 ] − g [ w ] [ 0 ] ) + s u m [ u ] )
下面考虑基环的情况,假设环上的点为 v1,...,vm v 1 , . . . , v m ,枚举 v1 v 1 的转移,即 v1 v 1 是否要通过购买 vm v m 赠送得到,以 sta=0/1 s t a = 0 / 1 表示 v1 v 1 不用/用通过购买 vm v m 赠送得到,以 dp[i][0] d p [ i ] [ 0 ] 表示购买 v1,...,vi v 1 , . . . , v i 以及其外挂着的树上所有节点至少一次所需最少代价, dp[i][1] d p [ i ] [ 1 ] 表示购买 v1,...,vi v 1 , . . . , v i 以及其外挂着的树上所有节点至少一次且以第二种优惠方式购买 vi v i 的最少代价,那么
dp[1][1]=g[v1][1],dp[1][0]=sta?sum[v1]:dp[v1][0] d p [ 1 ] [ 1 ] = g [ v 1 ] [ 1 ] , d p [ 1 ] [ 0 ] = s t a ? s u m [ v 1 ] : d p [ v 1 ] [ 0 ] ,并有转移
dp[i][1]=dp[i−1][0]+g[vi][1] d p [ i ] [ 1 ] = d p [ i − 1 ] [ 0 ] + g [ v i ] [ 1 ]
dp[i][0]=min(dp[i−1][1]+sum[vi],dp[i−1][0]+g[vi][0]) d p [ i ] [ 0 ] = min ( d p [ i − 1 ] [ 1 ] + s u m [ v i ] , d p [ i − 1 ] [ 0 ] + g [ v i ] [ 0 ] )
答案即为 dp[m][sta] d p [ m ] [ s t a ] ,枚举 sta s t a 选取较优值即为答案
Code
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
typedef long long ll;
#define maxn 100005
int n,p[maxn],d[maxn],f[maxn],vis[maxn],mark[maxn];
ll g[maxn][2],dp[maxn][2],sum[maxn];
vector<int>e[maxn];
void dfs(int u)
{
vis[u]=1;
ll mn=1e16;
for(int i=0;i<e[u].size();i++)
{
int v=e[u][i];
if(mark[v])continue;
dfs(v);
sum[u]+=g[v][0];
mn=min(mn,g[v][1]-g[v][0]);
}
g[u][1]=p[u]+sum[u];
g[u][0]=min(p[u]-d[u]+sum[u],mn+sum[u]);
}
ll Solve(int u)
{
while(!vis[u])vis[u]=1,u=f[u];
vector<int>v;
v.clear();
v.push_back(u);
while(f[v.back()]!=u)v.push_back(f[v.back()]);
for(int i=0;i<v.size();i++)mark[v[i]]=1;
for(int i=0;i<v.size();i++)dfs(v[i]);
ll ans=1e16;
for(int sta=0;sta<=1;sta++)
{
dp[0][1]=g[v[0]][1];
dp[0][0]=sta?sum[v[0]]:g[v[0]][0];
for(int i=1;i<v.size();i++)
{
dp[i][1]=g[v[i]][1]+dp[i-1][0];
dp[i][0]=min(dp[i-1][1]+sum[v[i]],dp[i-1][0]+g[v[i]][0]);
}
ans=min(ans,dp[v.size()-1][sta]);
}
return ans;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&p[i]);
for(int i=1;i<=n;i++)scanf("%d",&d[i]);
for(int i=1;i<=n;i++)
{
scanf("%d",&f[i]);
e[f[i]].push_back(i);
}
ll ans=0;
for(int i=1;i<=n;i++)
if(!vis[i])ans+=Solve(i);
printf("%lld\n",ans);
return 0;
}