热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

2020牛客暑期多校训练营DecrementontheTree(图论,set)

DecrementontheTree题目描述样例input:53123134245356110210310output:8121010题目大意给你

Decrement on the Tree


题目描述

在这里插入图片描述


样例

input:
5 3
1 2 3
1 3 4
2 4 5
3 5 6
1 10
2 10
3 10
output:
8
12
10
10


题目大意

给你一棵树,现在你可以选择其中的一条链,将其边上的权值都减一。并且每条边的权值不能为负数。要求最少要删除多少次(每次只能减一),才能使得整棵树的权值都是0。(只需要输出答案,而不是修改)
并且,在给出答案之后,会有qq次修改,将某一条边的权值改成另一个,这时你要再一次输出答案。


分析

首先看到题目有一种树剖的感觉,但是显然,求答案时无法很好地用树剖解决。

所以这题应该是要维护每条边的权值。我们不妨思考一下求答案的过程实际是什么。实际就是找最少的链将树覆盖,然后每条边的重叠次数都有限制。
由于每条链唯一地由两个端点决定,所以,我们不妨考虑一下一棵树被覆盖后的链的端点处在那些节点上。
在这里插入图片描述
如图,我已经将覆盖所用的链用不同的颜色标出。可以发现:



  • 如果出现图三的情况,即一个点相连的边的权值中MaxMax大于其他边的和,那么其他边可以通过MaxMax通向其他的节点作为终点,而MaxMax减去其他边总和数量的链只有将这个点作为端点了。这样,以这个点为端点个数就是MaxOthersMax-Others

  • 如果图二的情况,即没有一条边是大于其他边权和(虽然上图也是,但是请假装2不大于1:)),那么就要考虑欧拉回路的知识,如果是奇数,那么肯定有一个端点,如果是图一一样的偶数,那么可以做到这个点上没有端点。

那么用上述的方法可以求得整棵树上的端点个数,那么除以2就是链的个数了。

然后考虑修改的操作,我们只要维护一个multisetmultiset,由于每条边只会影响到相连的两个节点。然后找到要修改的值,直接修改就可以了。这里就大大体现了STLSTL的优势美滋滋。


代码

#include
#define ll long long
using namespace std;
const int MAXN=1e5+10;
ll len[MAXN],sum[MAXN],ans=0;//len 第i条边的权值 sum 第i个点的与之相连的边权和 ans 端点个数
pair<ll,ll> edge[MAXN];//第i条边的两个端点
multiset<ll> du[MAXN];//点相连的每条边权
multiset<ll>::iterator it;//迭代器
ll getnum(int x){//获取第x个节点的端点数it=--(du[x].end());//Maxif(*it>sum[x]-*it) return *it-(sum[x]-*it);//如果Max大于其他点return sum[x]&1;//如果点没有出现上述情况,考虑奇数偶数
}
void update(int id,int x,ll w){//修改的边编号为id,当前考虑的点为x,修改为wans-=getnum(x);//减去当前节点的du[x].erase(du[x].find(len[id]));du[x].insert(w);//删除之前这条边,然后插入新的sum[x]=sum[x]-len[id]+w;//更新x节点的边权和ans+=getnum(x);//重新算当前节点的端点数,并加入答案
}
int main()
{ll n,q,id,u,v,w;scanf("%lld%lld",&n,&q);for(int i=1;i<n;i++){scanf("%lld%lld%lld",&u,&v,&w);edge[i]=make_pair(u,v);len[i]=w;du[u].insert(w);du[v].insert(w);sum[u]+=w;sum[v]+=w;}//读入for(int i=1;i<=n;i++)ans+=getnum(i);printf("%lld\n",ans/2);//先算当前的答案while(q--){scanf("%lld%lld",&id,&w);ll u=edge[id].first,v=edge[id].second;//取出边的两个节点update(id,u,w);update(id,v,w);//修改答案和点的边权和len[id]=w;//修改边权printf("%lld\n",ans/2);}
}

END

multisetmultiset万岁!!!


推荐阅读
  • 本题要求在一组数中反复取出两个数相加,并将结果放回数组中,最终求出最小的总加法代价。这是一个经典的哈夫曼编码问题,利用贪心算法可以有效地解决。 ... [详细]
  • HDU 2871 内存管理问题(线段树优化)
    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2871。本题涉及内存管理操作,包括重置、申请、释放和查询内存块。通过使用线段树进行高效管理和维护。 ... [详细]
  • 本文深入探讨了UNIX/Linux系统中的进程间通信(IPC)机制,包括消息传递、同步和共享内存等。详细介绍了管道(Pipe)、有名管道(FIFO)、Posix和System V消息队列、互斥锁与条件变量、读写锁、信号量以及共享内存的使用方法和应用场景。 ... [详细]
  • 探讨 HDU 1536 题目,即 S-Nim 游戏的博弈策略。通过 SG 函数分析游戏胜负的关键,并介绍如何编程实现解决方案。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 主调|大侠_重温C++ ... [详细]
  • 软件工程课堂测试2
    要做一个简单的保存网页界面,首先用jsp写出保存界面,本次界面比较简单,首先是三个提示语,后面是三个输入框,然 ... [详细]
  • CSS高级技巧:动态高亮当前页面导航
    本文介绍了如何使用CSS实现网站导航栏中当前页面的高亮显示,提升用户体验。通过为每个页面的body元素添加特定ID,并结合导航项的类名,可以轻松实现这一功能。 ... [详细]
  • 本文介绍两道有趣的编程问题:一是寻找给定数字n的连续数字序列及其个数,二是模拟一个翻杯子的游戏。同时附带一道智商题供读者思考。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • This post discusses an issue encountered while using the @name annotation in documentation generation, specifically regarding nested class processing and unexpected output. ... [详细]
  • 二叉树的链表实现
    本文介绍了一种使用链表结构表示二叉树的方法。通过定义节点结构和相关操作函数,可以方便地创建、插入和遍历二叉树。 ... [详细]
  • 本文探讨了在 SQL Server 中使用 JDBC 插入数据时遇到的问题。通过详细分析代码和数据库配置,提供了解决方案并解释了潜在的原因。 ... [详细]
  • 本文详细介绍了一种高效的算法——线性筛法,用于快速筛选出一定范围内的所有素数。通过该方法,可以显著提高求解素数问题的效率。 ... [详细]
  • 本文旨在探讨如何利用决策树算法实现对男女性别的分类。通过引入信息熵和信息增益的概念,结合具体的数据集,详细介绍了决策树的构建过程,并展示了其在实际应用中的效果。 ... [详细]
author-avatar
滴滴答2502906673
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有