Codeforces Round #200 (Div. 1)D. Water Tree

Codeforces Round #200 (Div. 1)D. Water Tree

问题描述

给定一棵$n$个节点的树和一个初始值为$0$的容器,你需要进行$ m$次操作。每一次操作都是向某一叶子节点加入一定数量的水,且加入的数量不得为负数。每个非叶子节点的水量是其所有子节点水量之和。每个叶子节点的水量可以是任意非负整数。给定所有操作后,你需要求出每个节点的最终水量。

解题思路

我们可以通过树形动态规划来解决这个问题。

假设$dp[i]$表示 $i$ 节点的水量,$son[i]$表示 $i$ 的儿子节点,$fa[i]$表示 $i$ 的父节点。

对于一个非叶子节点$i$,它的水量只取决于其所有儿子节点的水量之和,即:

$dp[i]=\sum\limits_{j=1}^k dp[son[i][j]]$

对于一个叶子节点$i$,它的水量为其初始值$s_i$加上所有向它加水的数量之和,即:

$dp[i]=s_i+\sum\limits_{j=1}^k c_j$

其中$c_j$表示第$j$次向节点$i$加水的数量。

我们可以按照题目要求模拟每一次向节点加入水的过程。具体而言,设$u$为向该节点加水的叶子节点,$w$为加入的水量,则:

  • 将$s_u$加上$w$;
  • 向父节点$f$进行递归,使得其水量加上$w$;
  • 最后使用dfs进行$dp$数组的树形DP。

代码实现

下面是实现了上述思路的C++代码:

#include<bits/stdc++.h>
#define MAXN 100005
using namespace std;
int n,m,root,cnt,tot,head[MAXN],dfn[MAXN],leaf[MAXN],size[MAXN],son[MAXN],fa[MAXN],siz[MAXN],sizs[MAXN];
int w[MAXN];
bool v[MAXN];
struct Edge {
    int to,nxt;
} e[MAXN<<1];
inline int read() {
    int x=0,f=1; char c;
    while(!isdigit(c=getchar())) f=c=='-'?-1:1;
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
inline void add_edge(int u,int v) {
    e[++cnt]=(Edge){v,head[u]};
    head[u]=cnt;
}
inline void dfs1(int u,int fa) {
    dfn[++tot]=u;
    siz[u]=1;
    for(int i=head[u],v; i; i=e[i].nxt) {
        if((v=e[i].to)^fa) {
            dfs1(v,u);
            siz[u]+=siz[v];
            if(siz[v]>siz[son[u]]) son[u]=v;
        }
    }
}
inline void dfs2(int u,int fa,int topf) {
    fa[u]=topf,sizs[u]=w[u];
    if(son[u]) dfs2(son[u],u,topf),sizs[u]+=sizs[son[u]];
    for(int i=head[u],v; i; i=e[i].nxt) {
        if((v=e[i].to)^son[u] && v^fa[u]) dfs2(v,u,v);
    }
}
inline void dfs3(int u,int fa) {
    for(int i=head[u],v; i; i=e[i].nxt) {
        if((v=e[i].to)^fa) dfs3(v,u),siz[u]+=siz[v],sizs[u]+=sizs[v];
    }
}
inline void dfs4(int u,int fa,bool t) {
    if(t) {
        siz[u]=sizs[u];
        if(u==root) siz[u]+=tot-cnt;
    }
    for(int i=head[u],v; i; i=e[i].nxt) {
        if((v=e[i].to)^fa && (!son[u] || v^son[u])) dfs4(v,u,1);
    }
    if(t) {
        if(!son[u]) leaf[++leaf[0]]=u;
        if(u!=root) w[fa[u]]+=sizs[u],siz[u]+=siz[fa[u]];
    }
}
int main() {
    n=read(),m=read(),root=1;
    while(n--) {
        int u=read(),v=read();
        add_edge(u,v),add_edge(v,u);
    }
    dfs1(1,0),dfs2(1,0,1),dfs3(1,0),dfs4(1,0,0);
    while(m--) {
        int u=read(),v=read();
        w[u]+=v,printf("%lld\n",sizs[1]*w[root]),w[root]+=siz[u]*v-sizs[u];
    }
    return 0;
}

总结

"Codeforces Round #200 (Div. 1)D. Water Tree"这道题较难理解。我们可以通过模拟每一次向节点加水的过程来解决问题。需要注意的是,在计算非叶子节点的水量时,我们只需要遍历其所有的儿子节点即可。而在计算叶子节点的水量时,我们还需要累加所有向他加水的数量。完整的代码可以在Codeforces平台上找到该题目的原题链接进行提交以获得AC。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Codeforces Round #200 (Div. 1)D. Water Tree - Python技术站

(0)
上一篇 2023年3月28日
下一篇 2023年3月28日

相关文章

  • wordcloud是什么?

    Wordcloud,也叫做文字云或词云,是一种可视化展示文本数据的方式,在绘制过程中将文本中出现频率较高的单词以较大的字号呈现,而出现频率较低的单词会以较小的字号呈现,并使用不同的颜色、形状等进行美化渲染,让整个图像更具有美感和易读性。 Wordcloud的制作过程涵盖以下几个步骤: 准备文本数据。需要从相关数据源中获取相应的文本内容。 进行文本分词。根据具…

    其他 2023年4月16日
    00
  • Vue业务组件封装Table表格示例详解

    下面我会为你详细讲解“Vue业务组件封装Table表格示例详解”的完整攻略。 简介 在实际开发中,我们经常会遇到需要使用表格来呈现数据的场景。在Vue框架中,我们可以使用一些UI库中的表格组件,比如Element UI中的el-table组件。但是,在实际项目中,我们可能会需要自定义一些表格的样式或功能,这时候就需要对表格进行封装。本文就是为大家详细讲解如何…

    other 2023年6月25日
    00
  • Linux shell 提取文件名和目录名的方法

    Linux shell 中提取文件名和目录名的方法通常使用shell变量和一些特定命令。以下是提取文件名和目录名的几种方法: 使用$变量获取当前目录和文件名 在Linux shell中,我们可以使用一些特殊的变量获取当前目录和文件名。其中,$PWD变量表示当前目录的路径,$0变量表示当前脚本的文件名,$1变量表示脚本后的第一个参数(文件名)。 例如,我们可以…

    other 2023年6月26日
    00
  • C语言每日练习之字符串反转

    首先需要明确的是,C语言每日练习之字符串反转是一个比较基础的练习题目,可以帮助初学者巩固字符串相关知识点。下面我将给出详细的攻略。 题目描述 需要编写一个程序,将输入的字符串反转输出,并且不能使用任何现成的反转函数。 分析 要实现字符串的反转,我们需要逐个将字符取出,并将其放置在新的字符串中。其中,需要注意以下几点: 字符串是以\0结尾的。因此,需要在遍历过…

    other 2023年6月20日
    00
  • 深入了解Vue之组件的生命周期流程

    当我们在Vue中定义一个组件时,该组件拥有多个生命周期函数,这些函数可以帮助我们在特定时间点执行一些任务,从而让我们更好地控制组件。 Vue组件的生命周期函数可以分为三个阶段:创建阶段、更新阶段和销毁阶段,以下是对每个阶段及其相关生命周期函数的详细说明。 创建阶段 在创建阶段中,涉及到以下生命周期函数: beforeCreate:在实例创建之前调用。此时,该…

    other 2023年6月27日
    00
  • window.onload的页面加载技巧

    当我们打开一个网页的时候,浏览器会依次加载 HTML、CSS、JavaScript等资源,而 window.onload 事件会在所有资源都加载完成后才会触发。所以通过 window.onload 来执行 JavaScript 操作可以保证页面中的所有元素都已经加载完成,从而避免因为元素还未加载完毕而出现错误的情况。 下面就是 window.onload 页…

    other 2023年6月25日
    00
  • Chrome浏览器下载的文件名显示乱码怎么办?

    当我们使用Chrome浏览器下载文件时,有时会遇到文件名显示乱码的情况,这可能是由于下载文件的编码格式和系统的编码格式不一致所导致的。下面是解决这个问题的完整攻略: 1. 修改浏览器默认编码 Chrome浏览器默认的编码格式是UTF-8,可以尝试修改为GB2312或GBK等其他编码格式,以解决文件名乱码的问题。 具体步骤: 在浏览器地址栏中输入chrome:…

    other 2023年6月26日
    00
  • .Net遍历窗体上控件的方法

    下面我将详细讲解一下“.Net遍历窗体上控件的方法”的完整攻略。 基本知识 在.Net中,窗体上的控件可以看作是窗体的一种子元素,可以通过遍历窗体上所有控件的方式访问或者操作控件。 遍历窗体上的控件,可以使用递归算法,遍历窗体中的每个控件,并判断其是否为容器控件(如Panel、GroupBox等),如果是,则继续遍历该容器控件内的子控件,直到遍历到最后一个控…

    other 2023年6月27日
    00
合作推广
合作推广
分享本页
返回顶部