CF1578L Labyrinth
比较厉害的题。
简化问题,如果是不考虑吃能不能走的话,那很显然我们要求路径上最小边最大,这显然是重构树。
看能不能考虑建出重构树以后,往树上思考,能够发现,如果我每次吃了糖果,增加了宽度,那必然会造成一些边不能走,换言就是重构树上一些子树,我走不进去了。 这就把这个题转换成一个树上问题,我维护的是路径最小值最大,可以保证正确性。
如果一个子树 的点权小于当前宽度,那说明这个子树里面的所有点就必须要被吃完。因为要尽可能不留下点没吃,这说明我们可以从限制最大的点开始考虑。(不然以后体型变大无法吃了,不符合题意。)
因为要求求初始值最大,最值嘛,考虑动归吧。考虑设 表示走完以 为根的子树,能有的初始值最大是多少。
每个点(非叶子)有且仅有两个儿子 。考虑转移。
发现对于两个儿子,完整走完一个,再去走另一个,相交走一部分 去走 ,其实是不劣的,因为你无论怎么走,吃完全部以后,都要回到当前点 ,而这个点的点权是路径上的最小值,非常关键。(因为下面子树内的点权都会不小于它。)
这下就可以转移了啊,直接根据定义即可:
本质上就是分类讨论要先走 ,还是先走 的一个动态规划。
#include<bits/stdc++.h>
using namespace std;
const int N =4e5+10;
#define int long long
struct node{
int u,v,w;
}a[N];
int Ans[N],n,m,siz[N],v[N],F[N],c[N];
vector<int> g[N<<1];
int Find(int x){
return x==F[x]?x:F[x]=Find(F[x]);
}
bool cmp(node a,node b){
return a.w>b.w;
}
void Kuskral_CG(){
sort(a+1,a+m+1,cmp);
for(int i=1;i<=2*n-1;i++) F[i]=i;
int cnt=n;
for(int i=1;i<=m;i++){
int u=Find(a[i].u),v=Find(a[i].v);
if(u==v) continue;
cnt++,F[u]=cnt,F[v]=cnt,g[cnt].push_back(u),g[cnt].push_back(v),c[cnt]=a[i].w;
}
}
void dfs(int u,int fath){
if(g[u].size()==0) {siz[u]=v[u];return ;}
if(c[g[u][0]]>c[g[u][1]]) dfs(g[u][1],u),dfs(g[u][0],u);
else dfs(g[u][0],u),dfs(g[u][1],u);
siz[u]=siz[g[u][0]]+siz[g[u][1]]+v[u];
Ans[u]=min(c[u]-siz[g[u][0]],Ans[g[u][1]]-siz[g[u][0]]);
Ans[u]=max(Ans[u],min(c[u]-siz[g[u][1]],Ans[g[u][0]]-siz[g[u][1]]));
}
signed main(){
memset(Ans,0x7f,sizeof(Ans));
cin>>n>>m;
for(int i=1;i<=n;i++) cin>>v[i];
for(int i=1;i<=m;i++) cin>>a[i].u>>a[i].v>>a[i].w;
Kuskral_CG(),dfs(2*n-1,0);
cout<<((Ans[2*n-1]<=0)?-1:Ans[2*n-1]);
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现