CF1394D 题解
CF1394D Boboniu and Jianghu 题解
Links
Solution
可以处理出对于每个点,向下 \(b\) 递增的最小 \(a\) 之和 \(dp_{i,0}\) 和向下 \(b\) 递减的最小 \(a\) 之和 \(dp_{i,1}\)。令与一个点 \(u\) 相连的点中有 \(k_{1}\) 个 \(b\) 值大于点 \(u\) 的,剩余 \(k_{2}\) 个小于点 \(u\) 的,则该点贡献为 \(\max(k_{1},k_{2}) \times a_{u}\)。
对于个端点指出的边,若两端点的 \(b\) 值相等则既可以连接子树递增的链,又可以连接子树递减的链。我们先假设连接递增的链,然后贪心的改变一些链接情况。具体的,找到从链接递增改变到连接递减后改变最大的一部分进行改变。
利用 dfs 进行转移即可。
该部分代码:
void dfs(int u, int fa)
{
    int sum = 0, cnt_up = 0, cnt_down = 0;
    for (int i = head[u]; i; i = edge[i].nxt)
    {
        int v = edge[i].to;
        if (v == fa)
        {
            continue;
        }
        dfs(v, u);
        // 可以递增,可以递减
        if (points[u].b == points[v].b)
        {
            // 换一个的价值
            st[u].push_back(dp[v][1] - dp[v][0]);
            // 先假定递增
            ++cnt_up;
            sum += dp[v][0];
        }
        else if (points[u].b > points[v].b)
        {
            ++cnt_up;
            sum += dp[v][0];
        }
        else
        {
            ++cnt_down;
            sum += dp[v][1];
        }
    }
    sort(st[u].begin(), st[u].end());
    // 把多少个转换
    for (int i = 0; i <= st[u].size(); i++)
    {
        dp[u][0] = min(dp[u][0], sum + max(cnt_up, cnt_down + (u != 1)) * points[u].a);
        dp[u][1] = min(dp[u][1], sum + max(cnt_up + (u != 1), cnt_down) * points[u].a);
        --cnt_up, ++cnt_down; // 改变了一条边
        if (i < st[u].size())
        {
            sum += st[u][i];
        }
    }
}
注意到当 \(u = 1\) 时需要特殊转移,即两条链可以合并为一条。最终答案即为 \(\min(dp_{1,0},dp_{1,1})\)。
Codes
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define max_n 210101
void read(int &p)
{
    p = 0;
    int k = 1;
    char c = getchar();
    while (c < '0' || c > '9')
    {
        if (c == '-')
        {
            k = -1;
        }
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        p = p * 10 + c - '0';
        c = getchar();
    }
    p *= k;
    return;
}
void write_(int x)
{
    if (x < 0)
    {
        putchar('-');
        x = -x;
    }
    if (x > 9)
    {
        write_(x / 10);
    }
    putchar(x % 10 + '0');
}
void writesp(int x)
{
    write_(x);
    putchar(' ');
}
void writeln(int x)
{
    write_(x);
    putchar('\n');
}
int n;
struct node
{
    int to, nxt;
} edge[max_n << 1];
int head[max_n], tot;
void add(int u, int v)
{
    edge[++tot].to = v;
    edge[tot].nxt = head[u];
    head[u] = tot;
}
struct Point
{
    int a, b;
} points[max_n];
int dp[max_n][2];
vector<int> st[max_n];
void dfs(int u, int fa)
{
    int sum = 0, cnt_up = 0, cnt_down = 0;
    for (int i = head[u]; i; i = edge[i].nxt)
    {
        int v = edge[i].to;
        if (v == fa)
        {
            continue;
        }
        dfs(v, u);
        // 可以递增,可以递减
        if (points[u].b == points[v].b)
        {
            // 换一个的价值
            st[u].push_back(dp[v][1] - dp[v][0]);
            // 先假定递增
            ++cnt_up;
            sum += dp[v][0];
        }
        else if (points[u].b > points[v].b)
        {
            ++cnt_up;
            sum += dp[v][0];
        }
        else
        {
            ++cnt_down;
            sum += dp[v][1];
        }
    }
    sort(st[u].begin(), st[u].end());
    // 把多少个转换
    for (int i = 0; i <= st[u].size(); i++)
    {
        dp[u][0] = min(dp[u][0], sum + max(cnt_up, cnt_down + (u != 1)) * points[u].a);
        dp[u][1] = min(dp[u][1], sum + max(cnt_up + (u != 1), cnt_down) * points[u].a);
        --cnt_up, ++cnt_down; // 改变了一条边
        if (i < st[u].size())
        {
            sum += st[u][i];
        }
    }
}
signed main()
{
#if _clang_
    freopen("1.in", "r", stdin);
    freopen("1.out", "w", stdout);
#endif
    read(n);
    for (int i = 1; i <= n; i++)
    {
        read(points[i].a);
    }
    for (int i = 1; i <= n; i++)
    {
        read(points[i].b);
    }
    for (int i = 1, u, v; i < n; i++)
    {
        read(u), read(v);
        add(u, v);
        add(v, u);
    }
    memset(dp, 0x3f, sizeof(dp));
    dfs(1, 0);
    writeln(min(dp[1][0], dp[1][1]));
    return 0;
}
本文来自博客园,作者:cn_ryh,转载请注明原文链接:https://www.cnblogs.com/yuhang-ren/p/17523698.html
                    
                
                
            
        
浙公网安备 33010602011771号