P6594 [YsOI2020] 换寝室

news/发布时间2024/5/19 8:16:19

P6594 [YsOI2020] 换寝室

树上差分+树形 dp

题意:给定一棵树,每条边有边权,割掉一些边,使得被割掉的边边权和不超过 kk ,最小化剩余连通块点权极差的最大值。

看到最小化最大值,可以考虑二分

此时二分了 \(x\),那么每个连通块的极差都不能超过 \(x\)。考虑需要判断是否存在一个连通块的划分方式,使得满足条件并且代价不超过 \(k\),即最小化代价

考虑树形 dp。解决的问题是子树中满足条件的最小代价,然后可以加一个状态方便转移,考虑记录当前连通块的信息。设 \(f_{u,i}\) 表示划分完满足条件的 \(u\) 子树,包含 \(u\) 的连通块最小值为 \(a_i\) 的最小代价。转移枚举每个子树 \(v\) 是否与 \(u\) 在同一个连通块内。

\(f_{u,i}=\sum\min(f_{v,i},mn+val(u,v))\)

若最小值相同,那么无需断边;否则不在同一个连通块内,一定需要断边(不然肯定在一个连通块内)。这时候就有一个问题,有时候会出现不合法的情况,比如断边之后无法满足出现这样两个连通块。但是我们发现这种情况是不会更优的,也就是不会对答案产生贡献

考虑初始化,我们需要知道每个点的连通块中能够出现哪些最小值,限制是二分的 \(x\),只需要每个点跑一遍 dfs 即可

复杂度 \(O(n^2)\)

#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_backtypedef long long i64;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 810;
int n, m, k, l = iinf, r, ans;
int dep[N], anc[N][11], sz[N], w[N], a[N];
std::vector<int> e[N];
void dfs(int u, int fa) {dep[u] = dep[fa] + 1;anc[u][0] = fa;for(int i = 1; i <= 10; i++) anc[u][i] = anc[anc[u][i - 1]][i - 1];for(auto v : e[u]) {if(v == fa) continue;dfs(v, u);}
}
int lca(int u, int v) {if(dep[u] < dep[v]) std::swap(u, v);for(int i = 10; i >= 0; i--) if(dep[anc[u][i]] >= dep[v]) u = anc[u][i];if(u == v) return u;for(int i = 10; i >= 0; i--) if(anc[u][i] != anc[v][i]) u = anc[u][i], v = anc[v][i];return anc[u][0];
}
void dfs2(int u, int fa) {for(auto v : e[u]) {if(v == fa) continue;dfs2(v, u);w[u] += w[v];}
} //lca+树上差分
int now;
int vis[N], f[N][N];
void find(int u, int fa, int rt) {vis[u] = 1;for(auto v : e[u]) {if(v == fa) continue;if(a[v] < a[rt] || a[v] - a[rt] > now) continue; find(v, u, rt);}
} //包含 rt 的连通块中最小值是否可以是 a[rt]
void dfs3(int u, int fa) {int mn;for(auto v : e[u]) {if(v == fa) continue;mn = iinf;dfs3(v, u);for(int i = 1; i <= n; i++) mn = std::min(mn, f[v][i]);for(int i = 1; i <= n; i++) {f[u][i] += std::min(f[v][i], mn + w[v]);}}
}
bool check(int x) {now = x;for(int u = 1; u <= n; u++) {memset(vis, 0, sizeof(vis));find(u, 0, u);for(int i = 1; i <= n; i++) {if(vis[i]) f[i][u] = 0;else f[i][u] = iinf;}}dfs3(1, 0);for(int i = 1; i <= n; i++) {if(f[1][i] <= k) return true;}return false;
}
void Solve() {std::cin >> n >> m >> k;for(int i = 1; i <= n; i++) {std::cin >> a[i];l = std::min(l, a[i]), r = std::max(r, a[i]);}for(int i = 1; i < n; i++) {int u, v;std::cin >> u >> v;e[u].pb(v), e[v].pb(u);}dfs(1, 0);for(int i = 1; i <= m; i++) {int x, y;std::cin >> x >> y;int rt = lca(x, y);w[x]++, w[y]++, w[rt] -= 2;}dfs2(1, 0);r = r - l, l = 0;while(l <= r) {int mid = (l + r) >> 1;if(check(mid)) r = mid - 1, ans = mid;else l = mid + 1;}std::cout << ans << "\n";
}
int main() {std::ios::sync_with_stdio(false);std::cin.tie(nullptr);Solve();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.ulsteruni.cn/article/35835701.html

如若内容造成侵权/违法违规/事实不符,请联系编程大学网进行投诉反馈email:xxxxxxxx@qq.com,一经查实,立即删除!

相关文章

最小生成树 Kruskal 算法

Kruskal 算法 edge存储边起点、终点、边权 fa[x]存储x的父节点 1、先初始化父节点 2、按边的权排序(贪心思想) 3、如果不在同一集合内,把这条边加入最小生成树,并且合并两个集合,反之就跳过 4、最后根据连接的点是否是顶点的个数减一确定能否生成最小生成树 如下图,红色表示…

短视频app源码,一文带你轻松搞懂前端大文件上传思路

短视频app源码,一文带你轻松搞懂前端大文件上传思路文件上传是我们在平时开发短视频app源码中经常会遇到的业务,如果只是简单的文件上传那还不足以作为项目亮点,而当我们给它加上切片、续传的功能,就不一样了。本文会带大家搞明白这些功能的实现思路,主要聚焦于 前端 部分…

HBuildx如果启用IOS真机调试?

制作标准基座: 安装爱思助手(www.i4.cn),用爱思助手制作ipa签名。添加ipa文件: 添加Hbuildx所在目录:HBuilderX.3.7.3.20230223\HBuilderX\plugins\launcher\base下的iPhone_base.ipa 添加之后勾选,选择使用Apple ID签名,这里需要登录你的苹果ID,然后点开始签名。 签…

SD 2024 一轮省集

My Blogs Day 1 \(80+10+0\) 垫底。 T1 神秘题。人类智慧发现 \(S\) 不会太长,生成一个 \(10^6\) 的串,然后建一个类似线段树的结构。 预处理出数组 \(f_{i,j}\) 表示 \(T\) 的第 \(i\) 位匹配一个 \(S_j\) 能跳到最远的地方,可以类似倍增处理。 然后双指针在 \(S\) 上跑,复…

汽车集成化和去集成化的博弈

大家有没有发现,最近很多有关的汽车领先科技新闻,都不约而同地提到了“集成化”这个词。比如日前,哪吒汽车发布了浩智高效三合一增程器,具备了体积小、成本优、效率高、静谧性好的优点;特斯拉的后车架一体化设计也有“多米诺效应”,比如在今年,蔚来ES7已开始应用一体化压…

使用TpuLang转换模型的流程

下图(run_eval待测模型列表及参数)填写更多不同精度评估方式的命令字符串,比如图中已有imagenet分类与coco检测精度计算字符串;下图(run_eval待测模型列表及参数)中model_list_all填写模型名到参数的映射,比如:resnet18_qat的[0,0],其中第1个参数表示用postprocess_type_a…