2021-07-31:给定数组father,大小为N,表示一共有N个节点,father[i] = j 表示点i的父亲是点j, father表示的树一定是一棵树而不是森林,给定数组values,大小为N,values[i]=v表示节点i的权值是v。实现如下4个方法,保证4个方法都很快!1)让某个子树所有节点值加上v,入参:int head, int v;2)查询某个子树所有节点值的累加和,入参:int head;3)在树上从a到b的整条链上所有加上v,入参:int a, int b, int v;4)查询在树上从a到b的整条链上所有节点值的累加和,入参:int a, int b。

福大大 答案2021-07-31:

时间紧。见代码。

代码用golang编写。代码如下:

package main

import (
"fmt"
"math"
) func main() {
father := []int{1, 2, 3, 4, 5}
values := []int{6, 7, 8, 9, 10}
tc := NewTreeChain(father, values)
right := NewRight(father, values)
tc.addSubtree(11, 22)
right.addSubtree(11, 22)
tc.addSubtree(33, 44)
right.addSubtree(33, 44)
if tc.queryChain(33, 44) != right.queryChain(33, 44) {
fmt.Println("错误")
} else {
fmt.Println("正确")
}
} type TreeChain struct {
// 时间戳 0 1 2 3 4
tim int
// 节点个数是n,节点编号是1~n
n int
// 谁是头
h int
// 朴素树结构
tree [][]int
// 权重数组 原始的0节点权重是6 -> val[1] = 6
val []int
// father数组一个平移,因为标号要+1
fa []int
// 深度数组!
dep []int
// son[i] = 0 i这个节点,没有儿子
// son[i] != 0 j i这个节点,重儿子是j
son []int
// siz[i] i这个节点为头的子树,有多少个节点
siz []int
// top[i] = j i这个节点,所在的重链,头是j
top []int
// dfn[i] = j i这个节点,在dfs序中是第j个
dfn []int
// 如果原来的节点a,权重是10
// 如果a节点在dfs序中是第5个节点, tnw[5] = 10
tnw []int
// 线段树,在tnw上,玩连续的区间查询或者更新
seg *SegmentTree
} func NewTreeChain(father []int, values []int) *TreeChain {
ret := &TreeChain{}
// 原始的树 tree,弄好了,可以从i这个点,找到下级的直接孩子
// 上面的一大堆结构,准备好了空间,values -> val
// 找到头部点
ret.initTree(father, values)
// fa;
// dep;
// son;
// siz;
ret.dfs1(ret.h, 0)
// top;
// dfn;
// tnw;
ret.dfs2(ret.h, ret.h)
ret.seg = NewSegmentTree(ret.tnw)
ret.seg.build(1, ret.n, 1)
return ret
} func (this *TreeChain) initTree(father []int, values []int) {
this.tim = 0
this.n = len(father) + 1
this.tree = make([][]int, this.n)
this.val = make([]int, this.n)
this.fa = make([]int, this.n)
this.dep = make([]int, this.n)
this.son = make([]int, this.n)
this.siz = make([]int, this.n)
this.top = make([]int, this.n)
this.dfn = make([]int, this.n)
this.tnw = make([]int, this.n)
this.n--
cnum := make([]int, this.n)
for i := 0; i < this.n; i++ {
this.val[i+1] = values[i]
}
for i := 0; i < this.n; i++ {
if father[i] == i {
this.h = i + 1
} else {
cnum[father[i]]++
}
}
this.tree[0] = make([]int, 0)
for i := 0; i < this.n; i++ {
this.tree[i+1] = make([]int, cnum[i])
}
for i := 0; i < this.n; i++ {
if i+1 != this.h {
cnum[father[i]]--
this.tree[father[i]+1][cnum[father[i]]] = i + 1
}
}
} // u 当前节点
// f u的父节点
func (this *TreeChain) dfs1(u int, f int) {
this.fa[u] = f
this.dep[u] = this.dep[f] + 1
this.siz[u] = 1
maxSize := -1
for _, v := range this.tree[u] { // 遍历u节点,所有的直接孩子
this.dfs1(v, u)
this.siz[u] += this.siz[v]
if this.siz[v] > maxSize {
maxSize = this.siz[v]
this.son[u] = v
}
}
} // u当前节点
// t是u所在重链的头部
func (this *TreeChain) dfs2(u int, t int) {
this.tim++
this.dfn[u] = this.tim
this.top[u] = t
this.tnw[this.tim] = this.val[u]
if this.son[u] != 0 { // 如果u有儿子 siz[u] > 1
this.dfs2(this.son[u], t)
for _, v := range this.tree[u] {
if v != this.son[u] {
this.dfs2(v, v)
}
}
}
} // head为头的子树上,所有节点值+value
// 因为节点经过平移,所以head(原始节点) -> head(平移节点)
func (this *TreeChain) addSubtree(head int, value int) {
// 原始点编号 -> 平移编号
head++
// 平移编号 -> dfs编号 dfn[head]
this.seg.add(this.dfn[head], this.dfn[head]+this.siz[head]-1, value, 1, this.n, 1)
} func (this *TreeChain) querySubtree(head int) int {
head++
return this.seg.query(this.dfn[head], this.dfn[head]+this.siz[head]-1, 1, this.n, 1)
} func (this *TreeChain) addChain(a int, b int, v int) {
a++
b++
for this.top[a] != this.top[b] {
if this.dep[this.top[a]] > this.dep[this.top[b]] {
this.seg.add(this.dfn[this.top[a]], this.dfn[a], v, 1, this.n, 1)
a = this.fa[this.top[a]]
} else {
this.seg.add(this.dfn[this.top[b]], this.dfn[b], v, 1, this.n, 1)
b = this.fa[this.top[b]]
}
}
if this.dep[a] > this.dep[b] {
this.seg.add(this.dfn[b], this.dfn[a], v, 1, this.n, 1)
} else {
this.seg.add(this.dfn[a], this.dfn[b], v, 1, this.n, 1)
}
} func (this *TreeChain) queryChain(a int, b int) int {
a++
b++
ans := 0
for this.top[a] != this.top[b] {
if this.dep[this.top[a]] > this.dep[this.top[b]] {
ans += this.seg.query(this.dfn[this.top[a]], this.dfn[a], 1, this.n, 1)
a = this.fa[this.top[a]]
} else {
ans += this.seg.query(this.dfn[this.top[b]], this.dfn[b], 1, this.n, 1)
b = this.fa[this.top[b]]
}
}
if this.dep[a] > this.dep[b] {
ans += this.seg.query(this.dfn[b], this.dfn[a], 1, this.n, 1)
} else {
ans += this.seg.query(this.dfn[a], this.dfn[b], 1, this.n, 1)
}
return ans
} type SegmentTree struct {
MAXN int
arr []int
sum []int
lazy []int
} func NewSegmentTree(origin []int) *SegmentTree {
ret := &SegmentTree{}
ret.MAXN = len(origin)
ret.arr = origin
ret.sum = make([]int, ret.MAXN<<2)
ret.lazy = make([]int, ret.MAXN<<2)
return ret
} func (this *SegmentTree) pushUp(rt int) {
this.sum[rt] = this.sum[rt<<1] + this.sum[rt<<1|1]
} func (this *SegmentTree) pushDown(rt int, ln int, rn int) {
if this.lazy[rt] != 0 {
this.lazy[rt<<1] += this.lazy[rt]
this.sum[rt<<1] += this.lazy[rt] * ln
this.lazy[rt<<1|1] += this.lazy[rt]
this.sum[rt<<1|1] += this.lazy[rt] * rn
this.lazy[rt] = 0
}
} func (this *SegmentTree) build(l int, r int, rt int) {
if l == r {
this.sum[rt] = this.arr[l]
return
}
mid := (l + r) >> 1
this.build(l, mid, rt<<1)
this.build(mid+1, r, rt<<1|1)
this.pushUp(rt)
} func (this *SegmentTree) add(L int, R int, C int, l int, r int, rt int) {
if L <= l && r <= R {
this.sum[rt] += C * (r - l + 1)
this.lazy[rt] += C
return
}
mid := (l + r) >> 1
this.pushDown(rt, mid-l+1, r-mid)
if L <= mid {
this.add(L, R, C, l, mid, rt<<1)
}
if R > mid {
this.add(L, R, C, mid+1, r, rt<<1|1)
}
this.pushUp(rt)
} func (this *SegmentTree) query(L int, R int, l int, r int, rt int) int {
if L <= l && r <= R {
return this.sum[rt]
}
mid := (l + r) >> 1
this.pushDown(rt, mid-l+1, r-mid)
ans := 0
if L <= mid {
ans += this.query(L, R, l, mid, rt<<1)
}
if R > mid {
ans += this.query(L, R, mid+1, r, rt<<1|1)
}
return ans
} // 为了测试,这个结构是暴力但正确的方法
type Right struct {
n int
tree [][]int
fa []int
val []int
path map[int]int
} func NewRight(father []int, value []int) *Right {
ret := &Right{}
ret.n = len(father)
ret.tree = make([][]int, ret.n)
ret.fa = make([]int, ret.n)
ret.val = make([]int, ret.n)
for i := 0; i < ret.n; i++ {
ret.fa[i] = father[i]
ret.val[i] = value[i]
}
help := make([]int, ret.n)
h := 0
for i := 0; i < ret.n; i++ {
if father[i] == i {
h = i
} else {
help[father[i]]++
}
}
for i := 0; i < ret.n; i++ {
ret.tree[i] = make([]int, help[i])
}
for i := 0; i < ret.n; i++ {
if i != h {
help[father[i]]--
ret.tree[father[i]][help[father[i]]] = i
}
}
ret.path = make(map[int]int)
return ret
} func (this *Right) addSubtree(head int, value int) {
this.val[head] += value
for _, next := range this.tree[head] {
this.addSubtree(next, value)
}
} func (this *Right) querySubtree(head int) int {
ans := this.val[head]
for _, next := range this.tree[head] {
ans += this.querySubtree(next)
}
return ans
} func (this *Right) addChain(a int, b int, v int) {
this.path = make(map[int]int)
this.path[a] = math.MinInt64
for a != this.fa[a] {
this.path[this.fa[a]] = a
a = this.fa[a]
}
_, ok := this.path[b]
for !ok {
this.val[b] += v
b = this.fa[b]
}
this.val[b] += v
for this.path[b] != math.MaxInt64 {
b = this.path[b]
this.val[b] += v
}
} func (this *Right) queryChain(a int, b int) int {
this.path = make(map[int]int)
this.path[a] = math.MinInt64
for a != this.fa[a] {
this.path[this.fa[a]] = a
a = this.fa[a]
}
ans := 0
_, ok := this.path[b]
for !ok {
ans += this.val[b]
b = this.fa[b]
}
ans += this.val[b]
for this.path[b] != math.MinInt64 {
b = this.path[b]
ans += this.val[b]
}
return ans
}

左神java代码

2021-07-31:给定数组father,大小为N,表示一共有N个节点,father[i] = j 表示点i的父亲是点j, father表示的树一定是一棵树而不是森林,给定数组values,大小为N的更多相关文章

  1. [LeetCode]Subtree of Another Tree判断一棵树是不是另一棵树的子树

    将树序列化为字符串,空节点用符号表示,这样可以唯一的表示一棵树. 用list记录所有子树的序列化,和目标树比较. List<String> list = new ArrayList< ...

  2. PHP 一个树为另一棵树的子结构 [TO BE CONTINUED]

    输入两棵二叉树A,B,判断B是不是A的子结构.(ps:我们约定空树不是任意一个树的子结构) <?php class TreeNode { private $val; private $left; ...

  3. 判断一棵树是否为二叉搜索树(二叉排序树) python

    输入一棵树,判断这棵树是否为二叉搜索树.首先要知道什么是排序二叉树,二叉排序树是这样定义的,二叉排序树或者是一棵空树,或者是具有下列性质的二叉树: (1)若左子树不空,则左子树上所有结点的值均小于它的 ...

  4. SDUT 2129 树结构练习——判断给定森林中有多少棵树

    树结构练习——判断给定森林中有多少棵树 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description  众 ...

  5. A Simple Problem with Integers(100棵树状数组)

    A Simple Problem with Integers Time Limit: 5000/1500 MS (Java/Others)    Memory Limit: 32768/32768 K ...

  6. Codeforces - 828E DNA Evolution —— 很多棵树状数组

    题目链接:http://codeforces.com/contest/828/problem/E E. DNA Evolution time limit per test 2 seconds memo ...

  7. hdu6035 Colorful Tree 树形dp 给定一棵树,每个节点有一个颜色值。定义每条路径的值为经过的节点的不同颜色数。求所有路径的值和。

    /** 题目:hdu6035 Colorful Tree 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6035 题意:给定一棵树,每个节点有一个颜色值.定 ...

  8. Trees in a Wood. UVA 10214 欧拉函数或者容斥定理 给定a,b求 |x|<=a, |y|<=b这个范围内的所有整点不包括原点都种一棵树。求出你站在原点向四周看到的树的数量/总的树的数量的值。

    /** 题目:Trees in a Wood. UVA 10214 链接:https://vjudge.net/problem/UVA-10214 题意:给定a,b求 |x|<=a, |y|&l ...

  9. Codeforces Round #590 (Div. 3)【D题:26棵树状数组维护字符出现次数】

    A题 题意:给你 n 个数 , 你需要改变这些数使得这 n 个数的值相等 , 并且要求改变后所有数的和需大于等于原来的所有数字的和 , 然后输出满足题意且改变后最小的数值. AC代码: #includ ...

  10. Codeforces Round #590 (Div. 3)【D题:维护26棵树状数组【好题】】

    A题 题意:给你 n 个数 , 你需要改变这些数使得这 n 个数的值相等 , 并且要求改变后所有数的和需大于等于原来的所有数字的和 , 然后输出满足题意且改变后最小的数值. AC代码: #includ ...

随机推荐

  1. 利用Vue技术实现的查询所有和添加功能

    就是根据Vue本身的特性,对之前写过的JSON等进行页面代码的简化. 其中,有俩点,需要明白一下: 在body标签里面,使用div标签,将列表数据包住,并设置一个id,便于vue对其的引用 在使用vu ...

  2. something to SSSSay

    可能记录写博客的初衷,现在的状态,一些目标.想法. 首先让我拟定几个关键词: 半吊子程序员 咸鱼 欲求不满 终生学习 自律 <差不多程序员> 长得差不多(175)高,看着差不多(普通)帅, ...

  3. ctfshow VIP限免题目(最新)

    源码泄露 这一题主要考察如何查看网页源代码,查看方式主要有三种 在网页前面加上view-source: 右键页面,点击查看页面源代码 键盘上按下F12打开开发者工具,在查看器中查看源代码 这一题随便一 ...

  4. 选择KV数据库最重要的是什么

    本文分享自华为云社区<选择KV数据库最重要的是什么?>,作者:GaussDB 数据库 . 经常有客户提到KV数据库,但却偏偏"不要Redis".比如有个做安全威胁分析平 ...

  5. ArcGIS JS API加载带参数的rest服务参数被截掉问题处理

    我们在做一些项目的时候,会对ArcGIS的图层服务进行转发,增加一些权限参数以保证数据访问的安全, 但使用ArcGIS JS API加载的时候,对于rest服务?后增加的参数会被截掉. 为解决这个问题 ...

  6. 使用 SK 示例 探索 GitHub 存储库 中的机器人

    微软 3月22日 一篇文章"Semantic-kernel 嵌入和记忆:使用聊天UI探索GitHub Repos"[1] ,文章中进行了展示了嵌入,该文章解释了他们如何帮助开发人员 ...

  7. 【过滤器设计模式详解】C/Java/JS/Go/Python/TS不同语言实现

    简介 过滤器模式(Filter Pattern)或标准模式(Criteria Pattern),是一种结构型模式.这种模式允许使用不同的标准条件来过滤一组对象,并通过逻辑运算的方式把各条件连接起来,它 ...

  8. Windows下搭建java环境最新版本jdk运行jar文件

    1:安装JDK(Java Development Kit),链接https://www.oracle.com/java/technologies/downloads/#jdk18-windows下载最 ...

  9. 【从零开始】Docker Desktop:听说你小子要玩我

    前言 缘由 捡起遗忘的Docker知识 由于本狗近期项目紧任务重,高强度的搬砖导致摸鱼时间下降.在上线项目时,看到运维大神一系列骚操作,docker+k8s的知识如过眼云烟,忘得干净的很.所以想重新恶 ...

  10. Spring Boot 中使用 Redis

    Redis 环境 redis 安装.配置,启动:(此处以云服务器上进行说明) 下载地址:https://redis.io/download/ 下载后上传到云服务器上,如 /usr/local 中 gc ...