其他分享
首页 > 其他分享> > 2018牛客多校第三场B(基环树dp)

2018牛客多校第三场B(基环树dp)

作者:互联网

题目大意:

n ( ≤ 1 e 5 ) n(\le1e5) n(≤1e5)件商品,第 i i i件商品价格为 p [ i ] p[i] p[i],可以用以下两种折扣中的一种:

解题思路:

AC代码:

#include <bits/stdc++.h>
#define ft first
#define sd second
#define pb push_back
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0) //不能跟puts混用
#define seteps(N) fixed << setprecision(N)
#define endl "\n"
const int maxn = 1e5 + 10;
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int, int> pii;
const ll mod = 1e9 + 7;
const ll inf = 0x3f3f3f3f3f3f3f;
int n, cntc, f[maxn], cir[maxn];
ll sdp[maxn]; //sdp[i]存储的是以i为父节点的j的dp[j][0]总和
ll p[maxn], d[maxn], dp[maxn][2], g[maxn][2];
vector <int> G[maxn];
int vis[maxn];
ll ans = 0;
void solve2(int u) { //树上问题
    ll res = 0;
    dp[u][1] = p[u];
    dp[u][0] = p[u] - d[u];
    for (auto v : G[u]) {
        if (vis[v] == 2) continue;
        solve2(v);
        res += dp[v][0];
    }
    dp[u][1] += res, dp[u][0] += res;
    sdp[u] = res;
    for (auto v : G[u]) {
        if (vis[v] == 2) continue;
        vis[v]++;
        dp[u][0] = min(dp[u][0], res - dp[v][0] + dp[v][1]);
    }
}
void solve1(int id) { //
    cntc = 0;
    while (!vis[id]) vis[id]++, id = f[id];
    while (vis[f[id]] != 2) { //处理环上的点
        vis[f[id]]++;
        cir[++cntc] = id;    
        id = f[id];
    }
    for (int i = 1; i <= cntc; i++) {
        solve2(cir[i]); //解决以cir[i]为根的树上问题
    }
    // 处理环上问题:拆环为链
    /* 第一个点不是由最后一个点赠送 */
    ll res = inf;
    g[1][0] = dp[cir[1]][0], g[1][1] = dp[cir[1]][1];
    for (int i = 2; i <= cntc; i++) {
        g[i][1] = dp[cir[i]][1] + g[i - 1][0];
        g[i][0] = min(dp[cir[i]][0] + g[i - 1][0], g[i - 1][1] + sdp[cir[i]]);
    }
    res = min(res, g[cntc][0]);
    /* 第一个点是由最后一个点赠送 */
    g[1][0] = sdp[cir[1]], g[1][1] = dp[cir[1]][1];
    for (int i = 2; i <= cntc; i++) {
        g[i][1] = dp[cir[i]][1] + g[i - 1][0];
        g[i][0] = min(dp[cir[i]][0] + g[i - 1][0], g[i - 1][1] + sdp[cir[i]]);
    }
    res = min(res, g[cntc][1]);
    ans += res;
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> p[i];
    for (int i = 1; i <= n; i++) cin >> d[i];
    for (int i = 1; i <= n; i++) cin >> f[i], G[f[i]].pb(i);
    for (int i = 1; i <= n; i++) {
        if (!vis[i]) 
            solve1(i);
    }
    cout << ans << endl;
    return 0;
}

标签:cir,int,res,多校,son,牛客,第三场,id,dp
来源: https://blog.csdn.net/weixin_45691711/article/details/120626305