luogu P3647 [APIO2014] 连珠线

https://www.luogu.com.cn/problem/P3647

我写DP像cxk

发现只有两种连边的方式

在这里插入图片描述

假设最优的策略已经给了出来,那么一定存在选定某个点为根的时候,只存在第一种脸边的情况

于是跑换根DP即可

具体的话设\(f[u][0/1]\)表示\(u\)是否作为中间点\(u\)往上延伸,的最大得分

转移还是挺显然的

\(f[u][0]=\sum\limits_{v\in son} \max(f[v][0],f[v][1]+w[v])\)
\(w[v]\)表示\(fa[u]->u\)的边权

\(f[u][1]=f[u][0]+\max(w[v]+f[v][0] - \max(f[v][0],f[v][1]+w[v]))\)
就是把上面\(v\)的贡献\(\max(f[v][0],f[v][1]+w[v])\)挖掉,然后加上\(v\)作为起点 往上延伸的贡献\(w[v]+f[v][0]\)

换根看起来不太好换

\(f[u][1]\)因为涉及到最大值,所以要记录\(u\)的 儿子中的最大值和次大值

考虑换根转移

在这里插入图片描述

\(ls[u][0/1]\)表示图中圈出来的那蓝色部分,那\(ls[fa][0/1]\)表示的就是图中圈起来的绿色部分

因为\(f[u][1]\)转移维护最大值的时候没有维护到父亲的转移,所以要用\(ls[fa]\)来重新更新一下\(ls[u]\)

然后设\(g[u][0]\)表示以\(u\)为根的答案

然后按照上面说的转移即可

具体实现看代码吧

code:

#include<bits/stdc++.h>
#define N 400050
#define ll long long
using namespace std;
struct edge {
    int v, nxt, c;
} e[N << 1];
int p[N], eid;
void init() {
    memset(p, -1, sizeof p);
    eid = 0;
}
void insert(int u, int v, int c) {
    e[eid].v = v;
    e[eid].c = c;
    e[eid].nxt = p[u];
    p[u] = eid ++;
}

const ll inf = 1e18;
ll ma1[N], ma2[N], f[N][2], g[N][2], ls[N][2], w[N];
int son1[N], son2[N], n;
void dfs(int u, int fa) {
    ma1[u] = ma2[u] = - inf, son1[u] = son2[u] = 0;
    for(int i = p[u]; i + 1; i = e[i].nxt) {
        int v = e[i].v, c = e[i].c;
        if(v == fa) continue; w[v] = c;
        dfs(v, u);
        int o = max(f[v][0], f[v][1] + w[v]);
        f[u][0] += o;
        if(f[v][0] + w[v] - o > ma1[u]) son2[u] = son1[u], ma2[u] = ma1[u], ma1[u] = f[v][0] + w[v] - o, son1[u] = v;
        else if(f[v][0] + w[v] - o > ma2[u]) ma2[u] = f[v][0] + w[v] - o, son2[u] = v;
    }
    f[u][1] = f[u][0] + ma1[u];
}
void dfss(int u, int fa) {
    for(int i = p[u]; i + 1; i = e[i].nxt) {
        int v = e[i].v, c = e[i].c;
        if(v == fa) continue;
        if(son1[u] == v) swap(son1[u], son2[u]), swap(ma1[u], ma2[u]);
        ls[u][0] = g[u][0] - max(f[v][0], f[v][1] + w[v]);
        ls[u][1] = ls[u][0] + ma1[u];
        if(fa) ls[u][1] = max(ls[u][1], ls[u][0] + ls[fa][0] + w[u] - max(ls[fa][0], ls[fa][1] + w[u]));
        g[v][0] = f[v][0] + max(ls[u][0], ls[u][1] + w[v]);
        if(ma1[u] < ma2[u]) swap(son1[u], son2[u]), swap(ma1[u], ma2[u]);
        dfss(v, u);
    }
}
int main() {
    init();
    scanf("%d", &n);
    for(int i = 1; i < n; i ++) {
        int u, v, c;
        scanf("%d%d%d", &u, &v, &c);
        insert(u, v, c), insert(v, u, c);
    }
    dfs(1, 0); 
    g[1][0] = f[1][0];
    dfss(1, 0);
    // for(int i = 1; i <= n; i ++) printf("%lld ", f[i][0]); printf("\n");
    // for(int i = 1; i <= n; i ++) printf("%lld ", g[i][0]); printf("\n");
    ll ans = 0;
    for(int i = 1; i <= n; i ++) ans = max(ans, g[i][0]);
    printf("%lld", ans);
    return 0;
}
posted @ 2022-02-16 15:36  lahlah  阅读(46)  评论(0)    收藏  举报