2021江西 I-Homework

2021江西省赛 I. Homework

分析

本题的分析过程还是蛮有意思的,我们细说一下。

最后是用换根DP解决的,但是为什么能这么解决?

我们先只考虑查询操作

查询

对于每个点来说,拿它去更新其余点能完成作业的最短时间。

我们很容易就可以发现是个最短路了,但是这样跑的话时间复杂度直接炸掉了,O(n2logn)

但是,我们重新审视这个过程,可以发现。

我们其实就是把一个点当成根,向下去更新所有的点

也就是说,一个点只会被儿子或者父亲更新

那么其实,我们就考虑换根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;
}
posted @   艾特玖  阅读(26)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示