freeswitch 发update sip消息_LeetCode LCP 05——发 LeetCoin

关键字:线段树

归航return:(Trivial)LeetCode 1354——多次求和构造目标数组​zhuanlan.zhihu.com
归航return:(Trivial) LeetCode 84—柱状图中最大的矩形​zhuanlan.zhihu.com

Problem

力扣决定给一个刷题团队发 LeetCoin 作为奖励。同时,为了监控给大家发了多少 LeetCoin,力扣有时候也会进行查询。

该刷题团队的管理模式可以用一棵树表示:

  1. 团队只有一个负责人,编号为 1。除了该负责人外,每个人有且仅有一个领导(负责人没有领导);
  2. 不存在循环管理的情况,如 A 管理 B,B 管理 C,C 管理 A。

力扣想进行的操作有以下三种:

  1. 给团队的一个成员(也可以是负责人)发一定数量的 LeetCoin
  2. 给团队的一个成员(也可以是负责人),以及他/她管理的所有人(即他/她的下属、他/她下属的下属,……),发一定数量的LeetCoin
  3. 查询某一个成员(也可以是负责人),以及他/她管理的所有人被发到的 LeetCoin 之和。

输入:

  1. N表示团队成员的个数(编号为1~N,负责人为1);
  2. leadership是大小为(N - 1) * 2的二维数组,其中每个元素[a, b]代表ba的下属;
  3. operations 是一个长度为Q的二维数组,代表以时间排序的操作,格式如下:

operations[i][0] = 1: 代表第一种操作,operations[i][1] 代表成员的编号,operations[i][2] 代表 LeetCoin 的数量;

operations[i][0] = 2: 代表第二种操作,operations[i][1]代表成员的编号,operations[i][2] 代表 LeetCoin 的数量;

operations[i][0] = 3: 代表第三种操作,operations[i][1] 代表成员的编号;

输出:

返回一个数组,数组里是每次查询的返回值(发 LeetCoin 的操作不需要任何返回值)。由于发的 LeetCoin 很多,请把每次查询的结果模 1e9+7 (1000000007)

示例 1:

输入:N = 6, leadership = [[1, 2], [1, 6], [2, 3], [2, 5], [1, 4]], operations = [[1, 1, 500], [2, 2, 50], [3, 1], [2, 6, 15], [3, 1]]
输出:[650, 665]
解释:团队的管理关系见下图。
第一次查询时,每个成员得到的LeetCoin的数量分别为(按编号顺序):500, 50, 50, 0, 50, 0;
第二次查询时,每个成员得到的LeetCoin的数量分别为(按编号顺序):500, 50, 50, 0, 50, 15.

e5ff23f1a63f0e7fe30637ccb4734325.png

限制:

  1. 1 <= N <= 50000
  2. 1 <= Q <= 50000
  3. operations[i][0] != 3 时,1 <= operations[i][2] <= 5000
LCP 05. 发 LeetCoin - 力扣(LeetCode)​leetcode-cn.com

Solution

这里的问题就是区间修改,单点查询,区间查询,这类问题的正确解答,就是线段树。但是我们还需要正确地确定一个节点和其后续的所有节点的正确编号,保证节点和其后代在线段树的下标都是连续的。这个问题的解决方案就是利用树的遍历的先序遍历来进行求解。为此,我们需要维护一个 dfs 时间戳,当我们第一次访问到这个节点的时候,就对应的是节点的开始时间,完成先序遍历的递归算法完毕返回之后的时间戳,就刚好是节点的对应时间。这种算法称作 DFS 序

C++ 风格的伪代码如下:

void dfs(int idx, int& timeStamp){from[idx] = timeStamp;for (int next : adj[idx]){++timeStamp;dfs(next, timeStamp);}to[idx] = timeStamp;
}

当然,这里需要考虑下标问题,因此实际的实现中,我是将所有的坐标都减去 1,这样就可以映射到

中,使用一个大小为 n 的数组即可。在这么处理之后,操作 1 对应的就是在
[from[people], from[people]] 单点修改,2 对应的就是 [from[people], to[people]] 上区间修改,操作 3 对应的就是在 [from[people], to[people]] 上区间查询。起始时间点设定为 0,这样可以方便处理后续线段树的代码问题。

上述 test case 中,from 和 to 数组就是:

from: [0,1,2,5,3,4]to: [5,3,2,5,3,4]

这么做之前,我们还需要维护一个临接表,用于这个 dfs 操作:

vector<vector<int>> generateAdj(const vector<vector<int>>& leadership, int n){vector<vector<int>> adj(n);for (const auto & x : leadership){int src = x[0] - 1;int dst = x[1] - 1;adj[src].emplace_back(dst);}return adj;
}

注意,线段树的底层原理我并不是很懂,所以不会详细解释线段树的代码原理,而是当作黑箱子直接使用。代码如下:

class Solution {private int[] from;private int[] to;private List<Integer>[] adj;private int cnt;private static final int mod = (int)(1e9 + 7);public int[] bonus(int n, int[][] leadership, int[][] operations) {from = new int[n];to = new int[n];adj = new List[n];cnt = 0;int people = 0;int money = 0;for (int i = 0; i < n; ++i){adj[i] = new ArrayList<>();}for (int[] x : leadership){int src = x[0] - 1;int dst = x[1] - 1;adj[src].add(dst);}dfs(0);List<Integer> ans = new ArrayList<>();SegmentTree segmentTree = new SegmentTree(n);for (int[] operation : operations){switch (operation[0]){case (1):{people = operation[1] - 1;money = operation[2];segmentTree.update(from[people], from[people], money);break;}case (2):{people = operation[1] - 1;money = operation[2];segmentTree.update(from[people], to[people], money);break;}case (3):{people = operation[1] - 1;ans.add((int)(segmentTree.query(from[people], to[people]) % mod));break;}}}return ans.stream().mapToInt(i -> i).toArray();}private void dfs(int idx){from[idx] = cnt;for (int next : adj[idx]){++cnt;dfs(next);}to[idx] = cnt;}
}
class SegmentTree{private static class SegmentTreeSupport{private SegmentTreeSupport(){}public static int getLeftSon(int x){return x << 1;}public static int getRightSon(int x){return (x << 1) + 1;}public static int getFather(int x){if (x == 0){throw new IllegalArgumentException();}return x >> 1;}public final static int SEGMENT_TREE_FACTOR = 4;}private long[] tree, lazy;private final int length;private void rangeCheck(int index){if (index < 0 || index >= length){throw new IndexOutOfBoundsException(index);}}public SegmentTree(final int[] arr){if (arr == null || arr.length == 0){throw new IllegalArgumentException();}length = arr.length;tree = new long[SegmentTreeSupport.SEGMENT_TREE_FACTOR * length];lazy = new long[SegmentTreeSupport.SEGMENT_TREE_FACTOR * length];buildTree(arr, 0, length - 1, 1);}public SegmentTree(int n){this(new int[n]);}private void buildTree(final int[] arr, int fromIndex, int toIndex, int treeIndex){if (fromIndex == toIndex){tree[treeIndex] = arr[fromIndex];return;}int midIndex = (fromIndex + toIndex) >>> 1;buildTree(arr, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex));buildTree(arr, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex));collectSubMsgTo(treeIndex);}private void collectSubMsgTo(int treeIndex){//this line should be replaced by the function we want to maintain//that is: tree[treeIndex] = f(tree[leftIndex], tree[rightIndex])//if we want to maintain the range sumtree[treeIndex] = tree[SegmentTreeSupport.getLeftSon(treeIndex)] + tree[SegmentTreeSupport.getRightSon(treeIndex)];//if we want to maintain the minimum value
//        tree[treeIndex] = Math.min(tree[SegmentTreeSupport.getLeftSon(treeIndex)], tree[SegmentTreeSupport.getRightSon(treeIndex)]);//if we want to maintain the maximum value
//        tree[treeIndex] = Math.max(tree[SegmentTreeSupport.getLeftSon(treeIndex)], tree[SegmentTreeSupport.getRightSon(treeIndex)]);}private void getLazyStatus(int fromIndex, int toIndex, int treeIndex, long diff){//this line should be replaced by the function we want to maintain//now, we set the value to diff
//        lazy[treeIndex] = diff;
//        tree[treeIndex] = (long)(toIndex - fromIndex + 1) * diff;//if we want to add the value by diff, then code is:tree[treeIndex] += diff * (toIndex - fromIndex + 1);lazy[treeIndex] += diff;//if we want to set the value and maintain the minimum/maximum value
//        tree[treeIndex] = diff;
//        lazy[treeIndex] = diff;//if we want to add the value and maintain the minimum/maximum value
//        tree[treeIndex] += diff;
//        lazy[treeIndex] += diff;}private void push_down(int fromIndex, int toIndex, int treeIndex){int midIndex = (fromIndex + toIndex) >>> 1;getLazyStatus(fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex), lazy[treeIndex]);getLazyStatus(midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex), lazy[treeIndex]);lazy[treeIndex] = 0;}public void update(int updateFromIndex, int updateToIndex, long diff){rangeCheck(updateFromIndex);rangeCheck(updateToIndex);update(updateFromIndex, updateToIndex, 0, length - 1, 1, diff);}private void update(int updateFromIndex, int updateToIndex, int fromIndex, int toIndex, int treeIndex, long diff){if (updateFromIndex <= fromIndex && toIndex <= updateToIndex){getLazyStatus(fromIndex, toIndex, treeIndex, diff);return;}if (lazy[treeIndex] != 0){push_down(fromIndex, toIndex, treeIndex);}int midIndex = (fromIndex + toIndex) >>> 1;if (updateFromIndex <= midIndex){update(updateFromIndex, updateToIndex, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex), diff);}if (updateToIndex >= midIndex + 1){update(updateFromIndex, updateToIndex, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex), diff);}collectSubMsgTo(treeIndex);}public long query(int queryFromIndex, int queryToIndex){rangeCheck(queryFromIndex);rangeCheck(queryToIndex);if (queryFromIndex > queryToIndex){throw new IllegalArgumentException();}return query(queryFromIndex, queryToIndex, 0, length - 1, 1);}private long query(int queryFromIndex, int queryToIndex, int fromIndex, int toIndex, int treeIndex){if (queryFromIndex <= fromIndex && toIndex <= queryToIndex){return tree[treeIndex];}int midIndex = (fromIndex + toIndex) >>> 1;if (lazy[treeIndex] != 0){push_down(fromIndex, toIndex, treeIndex);}//if we want to maintain the range sumreturn (queryFromIndex <= midIndex ?query(queryFromIndex, queryToIndex, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex)): 0)+ (queryToIndex >= midIndex + 1? query(queryFromIndex, queryToIndex, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex)) :0);//if we want to maintain the minimum value
//        return Math.min(
//                (queryFromIndex <= midIndex ? query(queryFromIndex, queryToIndex, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex)) : Long.MAX_VALUE),
//                (queryToIndex >= midIndex + 1 ? query(queryFromIndex, queryToIndex, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex)) : Long.MAX_VALUE)
//        );//if we want to maintain the maximum value
//        return Math.max(
//                (queryFromIndex <= midIndex ? query(queryFromIndex, queryToIndex, fromIndex, midIndex, SegmentTreeSupport.getLeftSon(treeIndex)) : Long.MIN_VALUE),
//                (queryToIndex >= midIndex + 1 ? query(queryFromIndex, queryToIndex, midIndex + 1, toIndex, SegmentTreeSupport.getRightSon(treeIndex)) : Long.MIN_VALUE)
//        );}@Overridepublic String toString() {return "SegmentTreen" +"tree = " + Arrays.toString(tree) +", lazy = " + Arrays.toString(lazy);}
}

时间复杂度上,建立线段树和 DFS 的过程:

,每次查询的时间复杂度:
,总共有
次查询,因此总的时间复杂度是:

空间复杂度上,线段树加上 lazy 标记需要 8 倍的空间,fromto 是 1 倍的空间,因此是

EOF。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/490725.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

SpringMVC注解@RequestParam全面解析

在SpringMVC后台控制层获取参数的方式主要有两种&#xff0c;一种是request.getParameter("name")&#xff0c;另外一种是用注解RequestParam直接获取。这里主要讲这个注解 一、基本使用&#xff0c;获取提交的参数 后端代码&#xff1a; Java代码 RequestMapping(…

MATLAB(六)数据处理

一、Matlab中的默认数据文件mat文件 例1、把Matlab工作空间中的数据矩阵a、b、c保存到数据文件data1.mat中。 >> a [1, 2, 3] a 1 2 3 >> b [4, 5, 6] b 4 5 6 >> c [7, 8, 9] c 7 8 9 >> save data1 a b c 例2、把例1生…

java怎么安装_Windows、Linux、Mac下安装JDK

前言在知乎上看到很多童鞋在学Java的时候&#xff0c;因为安装jdk时没有正确的配置&#xff0c;会遇到很多问题。所以决定今天写一下jdk在Windows、Mac、Linux下都怎么安装。下载JDK“巧妇难为无米之炊”&#xff0c;所以首先我们要去Oracle官网上下载jdk&#xff0c;Java8下载…

200年历史的神经科学难题,取得重大突破

图片来源&#xff1a;Diogo Matias&#xff0c;Champalimaud基金会来源&#xff1a;中国生物技术网北京时间8月13日&#xff0c;发表在《Nature Neuroscience》上的一项研究&#xff0c;来自葡萄牙里斯本Champalimaud未知中心的研究团队解决了一个长达200年历史的神经科学难题。…

关系数据库SQL之可编程性触发器

前言 前面关系数据库SQL之可编程性函数&#xff08;用户自定义函数&#xff09;一文提到关系型数据库提供了可编程性的函数、存储过程、事务、触发器及游标&#xff0c;前文已介绍了函数、存储过程、事务&#xff0c;本文来介绍一下触发器的使用。(还是以前面的银行系统为例) 概…

图像处理:图像特效之油画效果

利用OpenCVpython对图片进行处理产生油画的效果 算法可以分为五步&#xff1a; 1、获取图像的灰度(gray)图片2、设计一个小方框&#xff08;4x4 or 8x8 or 10x10等&#xff09;&#xff0c;统计每个小方框的像素值3、将0-255的灰度值划分成几个等级&#xff0c;并把第二步处理…

socket模拟http的登陆_python模拟登陆知乎(最新版)

为啥要写这一篇文章呢&#xff1f;&#xff08;主要是qq群内有人在模拟登陆知乎&#xff0c;一直不成功&#xff09;然后我抓包看了下&#xff0c;发现知乎登陆页已经改版了&#xff0c;而且难度大大提高了。开始抓包首先内&#xff0c;还是打开知乎首页&#xff0c;然后输入账…

基于wrapper的特征选择——递归特征消除RFE的python实现

class sklearn.feature_selection.RFE(estimator, *, n_features_to_selectNone, step1, verbose0) https://scikit-learn.org/stable/modules/generated/sklearn.feature_selection.RFE.html?highlightrfe#sklearn.feature_selection.RFE estimator&#xff1a;用于特征选…

图像识别:利用KNN实现手写数字识别(mnist数据集)

图像识别&#xff1a;利用KNN实现手写数字识别&#xff08;mnist数据集&#xff09; 步骤&#xff1a; 1、数据的加载&#xff08;trainSize和testSize不要设置的太大&#xff09; 2、k值的设定&#xff08;不宜过大&#xff09; 3、KNN的核心&#xff1a;距离的计算 4、k个最近…

寻找数组中第K频繁的元素

问题是&#xff1a;给你一个数组&#xff0c;求解出现次数第K多的元素。当然leetcode上的要求是算法复杂度不能大于O(N*logN)。 首先这个问题我先是在leetcode上看到&#xff0c;当时想了两种做法&#xff0c;做到一半都觉得不是很好&#xff0c;正在思考别的方法。然后在牛客网…

一个与生命起源有关的悖论终于得到了解决

来源&#xff1a;原理当Caitlin Cornell低头看显微镜时&#xff0c;她看见黑色的背景下浮现出一些大大的明亮斑点。它们就像微缩的太阳&#xff0c;在深色的太空幕布下闪耀着光芒。Conell回忆起把这些斑点展示给她的导师Sarah Keller时的兴奋&#xff0c;那时她们意识到&#x…

python ffmpy3与FFmpeg的安装

python ffmpy3与FFmpeg的安装 安装命令&#xff1a; pip install ffmpy3 去官网下载FFmpeg&#xff0c;根据自身电脑版本下载相应安装包 http://ffmpeg.org/download.html from ffmpy3 import FFmpeg ff FFmpeg(inputs{test.mp4: None},outputs{output.ts: None}) print(f…

千兆网线8根线定义图_家中的网线断裂/不够长,如何接线才最合适?

网线作为互联网时代不可或缺的主角&#xff0c;更是家装布线和工程施工中的常客。网线相对来说是很脆弱的&#xff0c;特别是一些质量一般的网线&#xff0c;在很多情况下都可能会被弄断&#xff0c;比如老鼠咬、过度拉伸、摆在地下人踩的人多了、电起火烧断、不小心被夹断等等…

中国决定以“六大政策”推动新一代人工智能发展

来源&#xff1a;智造智库以新一代人工智能为代表的新一轮科技革命和产业变革已经呈现出强大的影响力和生命力&#xff0c;人工智能技术对生产、流通、消费等形成高度渗透、跨界融合&#xff0c;新业态、新模式不断涌现&#xff0c;给以往的产业生态、社会分工、行业和企业边界…

第三次站立会议

项目进展&#xff1a;项目主体开始实施&#xff0c;我们在前期分工准备的同时开始讨论连连看的具体式样&#xff0c;开始上网参考其他项目的式样&#xff0c;搜集图片素材&#xff0c;为具有我们特色的连连看项目做准备。 存在问题&#xff1a;搜集素材时组员对项目的风格式样见…

ffmpy3与ffmpeg的简单使用

安装 python ffmpy3与ffmpeg的安装 https://blog.csdn.net/qq_40962368/article/details/90748852 ffmpy3的介绍&#xff1a; https://ffmpy3.readthedocs.io/en/latest/ ffmpy3是一个用于FFmpeg的Python包装器&#xff0c;最初是从ffmpy项目派生出来的。它根据提供的参数及…

C++ vector查找某个特定元素是否存在

使用find()函数需要#include<algorithm> if (std::find(v.begin(), v.end(), key) ! v.end()) 从find函数的返回结果与vector的end比较可以看出其实这是一个指针&#xff0c;那么如果我们想要获得索引那么将返回结果与begin做差即可 find(v.begin(), v.end(), key)-v…

python列表应用案例-python列表使用实例

#以下是我自己在联系列表中所编写的语句&#xff1a; names["zangsan","lisi","wangermazi","Xiaoliuzi","dabiaoge","牛erbiaodi"] #----------0--------1---------2---------------3----------4---------5-----…

边工作边刷题:70天一遍leetcode: day 7

Max Points on a Line 要点&#xff1a;这题暴力解是用任何两点确定一条直线&#xff0c;然后对其他点检查是否共线&#xff0c;显然&#xff0c;这里没用空间来存储之前的检查结果&#xff0c;所以time complexity是O(n^3)。这题的难点是如何存储从而实现O(n^2)解。思路是另一…