2021江西 I-Homework
分析
本题的分析过程还是蛮有意思的,我们细说一下。
最后是用换根DP解决的,但是为什么能这么解决?
我们先只考虑查询操作
查询
对于每个点来说,拿它去更新其余点能完成作业的最短时间。
我们很容易就可以发现是个最短路了,但是这样跑的话时间复杂度直接炸掉了,
但是,我们重新审视这个过程,可以发现。
我们其实就是把一个点当成根,向下去更新所有的点
也就是说,一个点只会被儿子或者父亲更新
那么其实,我们就考虑换根DP
第一次dfs,我们求的dp(u)即为,只考虑u下面的子树的节点,所能最早完成作业的时间
第一次dfs,我们求的dp(u)即为,只考虑u的父亲对u的更新
就结束了
AC_code
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10,M = N<<1;
int h[N],ne[M],e[M],id[M],idx;
int a[N],val[N],dp[N];
int n,q;
void add(int a,int b,int c)
{
e[idx] = b,ne[idx] = h[a],id[idx] = c,h[a] = idx++;
}
void dfs1(int u,int fa)
{
dp[u] = a[u];
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(j==fa) continue;
dfs1(j,u);
dp[u] = min(dp[u],dp[j]+val[id[i]]);
}
}
void dfs2(int u,int fa)
{
for(int i=h[u];~i;i=ne[i])
{
int j = e[i];
if(j==fa) continue;
dp[j] = min(dp[j],dp[u]+val[id[i]]);
dfs2(j,u);
}
}
int main()
{
scanf("%d%d",&n,&q);
memset(h,-1,sizeof h);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n-1;i++)
{
int u,v,c;
scanf("%d%d%d",&u,&v,&c);
add(u,v,i),add(v,u,i);
val[i] = c;
}
while(q--)
{
int op;scanf("%d",&op);
if(op==1)
{
int x,y;scanf("%d%d",&x,&y);
a[x] = y;
}
else if(op==2)
{
int x,y;scanf("%d%d",&x,&y);
val[x] = y;
}
else
{
dfs1(1,-1),dfs2(1,-1);
int ans = 0;
for(int i=1;i<=n;i++) ans ^= dp[i];
printf("%d\n",ans);
}
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现