CF1394D
所谓单调递增或单调递减,其实只用看成一条有向的链,b 大的点指向 b 小的点即可。
所以对于边 (u,v),假设 bu≠bv,那么这条边的方向确定。
一个点对答案的贡献是经过它的链数,设 x 为指向它的边的数量,y 为它指出去的边的数量,那么贡献就是 ai×max(x,y)。
问题等价于你需要给两端高度相等的边确定方向最小化贡献和。
设 fu,0/1 表示以 u 为根的子树,u 到父亲的边强制为连入 / 连出情况下的最小贡献和。
更具体的,问题变成给定 m 个二元组 (fv,0,fv,1) 给每个二元组选择一个权值,然后设 x,y 分别为 0/1 的数量,贡献和加上 au×max(x,y)。
可以先假设不确定的所有元素选 0,然后依次枚举 1 的数量,不难发现我们肯定优先选 fv,1−fv,0 尽可能小的元素。
然后即时更新一下贡献,特判一下根节点,这个题就做完了。
时间复杂度 O(nlogn)。
Code:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 200005;
int n;
int a[N], b[N];
ll f[N][2];
int head[N], ver[N*2], nxt[N*2], cnt;
vector <ll> tmp[N];
void add(int u, int v) {
ver[++cnt] = v, nxt[cnt] = head[u], head[u] = cnt;
}
void chkmin(ll &a, ll b) { if (a > b) a = b; }
void dfs(int u, int fa) {
ll sum = 0, cnt1 = 0, cnt2 = 0;
for (int i = head[u]; i; i = nxt[i]) {
int v = ver[i];
if (v == fa) continue;
dfs(v, u);
if (b[v] == b[u]) tmp[u].push_back(f[v][1] - f[v][0]), sum += f[v][0], ++cnt1;
else if (b[v] > b[u]) sum += f[v][1], ++cnt2;
else sum += f[v][0], ++cnt1;
}
sort(tmp[u].begin(), tmp[u].end());
for (int i = 0; i <= tmp[u].size(); ++i) {
chkmin(f[u][0], sum + max(cnt1, cnt2 + (u != 1)) * a[u]);
chkmin(f[u][1], sum + max(cnt1 + (u != 1), cnt2) * a[u]);
--cnt1, ++cnt2;
if (i < tmp[u].size()) sum += tmp[u][i];
}
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
for (int i = 1; i <= n; ++i) scanf("%d", &b[i]);
for (int i = 1, u, v; i < n; ++i) scanf("%d%d", &u, &v), add(u, v), add(v, u);
memset(f, 0x3f, sizeof f);
dfs(1, 0);
printf("%lld", min(f[1][0], f[1][1]));
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!