前置知识点

dfs遍历
树状数组/线段树知识

链接

I题 求和.

题意

已知有 n 个节点,有 n−1 条边,形成一个树的结构。
给定一个根节点 k,每个节点都有一个权值,节点i的权值为 vi
给 m 个操作,操作有两种类型:
1 a x :表示将节点 a 的权值加上 x
2 a :表示求 aa 节点的子树上所有节点的和(包括 a 节点本身)

坑爹的是什么?坑爹的是结点个数和操作数都是1e6级别的!

思路

第一次尝试,就是正常的dfs建树,然后dfs求出子树和,更新就老老实实向上更新,把更新求完sum的target设为1。。。

然后就老老实实地TLE了。
最坏情况可是一个1e6的树链呀!这样就O(n^2)怎么都不够了。

正确的思路:dfs序+树状数组


(一)dfs
首先需要dfs搞一下树。黑色序号为默认的输入顺序,红色编号为dfs的遍历顺序。我们需要使用红色的编号作为dfs序。为什么呢?我们可以看到,使用了红色编号之后,每个结点的子树编号都是连续的了
(以下编号皆为红色的dfs序)
结点1:1~6
结点2:2~4
结点3:3~3
结点4:4~4
结点5:5~5
结点6:6~6

我们在dfs遍历的同时,把每个结点的子树结点(包括本身)的起始坐标和末坐标保存在数组in[] 和数组out[]里面

当然你也可以设置一个dfn[] 序列
dfn[i]=j 表示红色编号i代表的是黑色编号j的点 【好绕啊有没有!】

见代码!

int Time=0; ///时间戳
void dfs(int x,int fa){in[x]=++Time;for(int i=0;i<P[x].size();++i){int v=P[x][i];if(v!=fa)dfs(v,x);}out[x]=Time;
}

(二)树状数组
我们搞了那么久,就是让维护的区间都是一段连续的。
比如对于结点i的子树和那就等于in[i] ~ out[i] 之间的和

那就使用线段树或者树状数组吧!这里树状数组方便一丢丢。

首先树状数组基本代码搞出来!

ll c[MAX];
ll lowbit(int x){return x&(-x);
}
ll query(int x){ll ans = 0ll;while(x){ans += c[x];x -= lowbit(x);}return ans;
}
void update(int x,ll v){while(x <= n){c[x] += v;x += lowbit(x);}
}

很明显,因为只有dfs序的序列才应该是树状数组所维护的c[]数组,而不是原来就输入的a[]数组。

我们每次更新,更新的下标为时间戳Time(就是dfs序的当前下标),更新的值为a[x],即当前dfs到的那个数的值。

void dfs(int x,int fa){in[x]=++Time;update(Time,a[x]);            ///这里加上这句!for(int i=0;i<P[x].size();++i){int v=P[x][i];if(v!=fa)dfs(v,x);}out[x]=Time;
}

而对于之后的操作中的更新,我们也有办法。
对于结点x,in[x]就是该结点的dfs序,那么就简单了

if(ope==1){cin >> p1 >> p2;update(in[p1],p2);   ///下标和增加值
}

对于询问操作,因为结点x管理的子树范围是从in[x] ~ out[x],而树状数组的询问操作又是前缀和,因此我们使用一个差就可以了!注意in那里需要减掉一个1,这样才能保证差就是in[x] ~ out[x]的值。

cout << query(out[p1])-query(in[p1]-1)<< endl;

完整代码如下!

#include <bits/stdc++.h>
#define show(x) std::cerr << #x << "=" << x << std::endl
#define IOS ios_base::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
using namespace std;
/** freopen("input.in", "r", stdin);freopen("output.out", "w", stdout);*/
typedef long long ll;
const int MAX=1e6+50;
const int INF=1e9;
const double EPS = 0.001;
const ll MOD=1e9+7;
vector<int>P[MAX];
int in[MAX],out[MAX];
int n,Time;
int a[MAX];
ll c[MAX];
ll lowbit(int x){return x&(-x);
}
ll query(int x){ll ans = 0ll;while(x){ans += c[x];x -= lowbit(x);}return ans;
}
void update(int x,ll v){while(x <= n){c[x] += v;x += lowbit(x);}
}
void dfs(int x,int fa){in[x]=++Time;update(Time,a[x]);for(int i=0;i<P[x].size();++i){int v=P[x][i];if(v!=fa)dfs(v,x);}out[x]=Time;
}
int main()
{IOS;int m,k;cin >> n >> m >> k;for(int i=1;i<=n;++i){cin >> a[i];}for(int i=1;i<n;++i){int va,vb;cin >> va >> vb;P[va].push_back(vb);P[vb].push_back(va);}dfs(k,0);for(int i=0;i<m;++i){int ope,p1;ll p2;cin >> ope;if(ope==1){cin >> p1 >> p2;update(in[p1],p2);}else{cin >> p1;///show(p1);show(in[p1]);show(out[p1]);cout << query(out[p1])-query(in[p1]-1)<< endl;}}return 0;
}
/**
5 6 1
1 2 3 4 5
1 3
1 2
2 4
2 5
1 2 10
1 3 10
1 4 5
1 5 1
2 3
2 2====
output:
13
27
*/

这题也是经过一些dl的指点和百度、看了很多代码才明白的!
(之前还没听说过dfs序这种东东唔唔)
当时之后写的时候用线段树写一直段错误和WA,差点自闭

相信一切都会好起来的!

【dfs序+树状数组】多次更新+求结点子树和操作,牛客小白月赛24 I题 求和相关推荐

  1. 计蒜客(青出于蓝胜于蓝) dfs序+树状数组

    武当派一共有 n 人,门派内 n 人按照武功高低进行排名,武功最高的人排名第 1,次高的人排名第 2,... 武功最低的人排名 第 n.现在我们用武功的排名来给每个人标号,除了祖师爷,每个人都有一个师 ...

  2. HDU - 5788 Level Up(主席树+dfs序+树状数组)

    题目链接:点击查看 题目大意:给出一棵有向树,每个节点都有一个初始的权值 a[ i ] ,和一个通过计算得到的权值 mid[ i ] ,mid 数组的计算方法如下:mid[ u ] 为结点 u 及其子 ...

  3. [Split The Tree][dfs序+树状数组求区间数的种数]

    Split The Tree 时间限制: 1 Sec  内存限制: 128 MB 提交: 46  解决: 11 [提交] [状态] [讨论版] [命题人:admin] 题目描述 You are giv ...

  4. 【POJ - 3321】 Apple Tree(dfs序 + 线段树维护 或 dfs序 + 树状数组维护)

    题干: There is an apple tree outside of kaka's house. Every autumn, a lot of apples will grow in the t ...

  5. 【BZOJ2434】[NOI2011]阿狸的打字机 AC自动机+DFS序+树状数组

    [BZOJ2434][NOI2011]阿狸的打字机 Description 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P ...

  6. 【bzoj2434】[Noi2011]阿狸的打字机 AC自动机+Dfs序+树状数组

    题目描述 阿狸喜欢收藏各种稀奇古怪的东西,最近他淘到一台老式的打字机.打字机上只有28个按键,分别印有26个小写英文字母和'B'.'P'两个字母. 经阿狸研究发现,这个打字机是这样工作的: l 输入小 ...

  7. CF-547E(Mike and Friends)后缀数组+线段树 AC自动机+DFS序+树状数组

    题目链接 题意 NNN个串,每次询问区间[L,R][L,R][L,R]中有多少子串SiS_iSi​ 思路 把NNN个串合成一个长字符串,对这个长字符串求后缀数组,包含SiS_iSi​的子串的heigh ...

  8. HDU - 5877 Weak Pair (dfs序+树状数组+离散化)

    VJ地址 题意:给一个有根树给你,计算一下满足下列条件的序列对的数目 (1)u是v的祖先(不能是它自己) (2)a[v]*a[u]<=k 思路:用DFS序分裂每一条链,使链上的点都是当前加入点的 ...

  9. 2018蓝桥杯模拟赛·青出于蓝而胜于蓝 DFS序+树状数组

    武当派一共有 nnn 人,门派内 nnn 人按照武功高低进行排名,武功最高的人排名第 111,次高的人排名第 222,... 武功最低的人排名第 nnn.现在我们用武功的排名来给每个人标号,除了祖师爷 ...

最新文章

  1. UI开发模式-容器模式
  2. 利用百度api判断已知经纬度的一个点是否在多边形内
  3. 全国计算机等级考试题库二级C操作题100套(第51套)
  4. python读取mysql以html形式输出_python实现处理mysql结果输出方式
  5. 过滤序列,惰性序列_Java 8的惰性序列实现
  6. python猜猜我是几,我在python中猜数游戏的问题
  7. 文件分片_怎样屏蔽QQ和微信外发文件,同时允许发送截图
  8. 安卓学习笔记05:Activity概述
  9. 5-Mybatis 的输出结果封装
  10. Discuz!NT 模板机制分析
  11. python图像风格迁移教程_【人工智能】python图像风格迁移,来欣赏梵高风格的石原里美吧!...
  12. Flutter 实战之dart语言
  13. openwrt设置DNS
  14. 网站分析平台:是选择百度统计,还是 Google Analytics 呢?
  15. thingworx项目-mushup
  16. 【acm2629】 Identity Card
  17. 使用c语言函数使二数相减,什么是c语言
  18. 差异表达分析(DEG)时 row.names'里不能有重复的名字 的解决方案
  19. 第一次社招笔试题回顾(全基础题)
  20. 网页防封链接制作的原理有哪些?

热门文章

  1. NCBI的NT库比对——blastn
  2. struts2 拦截器和过滤器理解
  3. 在 Spring Boot 中使用 HikariCP 连接池
  4. 在线ocr证件识别软件如何使用?
  5. 中国柔性制造系统(FMS)市场发展动态及未来趋势预测报告2022~2028年
  6. 【ACM程序设计实验】高分课程实验报告分享
  7. idea Java 读取rtf文件内容,解决中文乱码的问题。
  8. 计算机网络笔记(5) 传输层滑动窗口协议(GBN、SR)
  9. 阿里:Java工程师,算法工程师,数据挖掘分析工程师、测试开发工程师
  10. leetcode2021年度刷题分类型总结(八)贪心 (python)