牛客网 华华和月月种树(dfs序+区间更新树状数组)

题目链接:https://ac.nowcoder.com/acm/problem/23051

题目描述

华华看书了解到,一起玩养成类的游戏有助于两人培养感情。所以他决定和月月一起种一棵树。因为华华现在也是信息学高手了,所以他们种的树是信息学意义下的。
华华和月月一起维护了一棵动态有根树,每个点有一个权值。刚开存档的时候,树上只有 0 号节点,权值为 0 。接下来有两种操作:
操作 1:输入格式1 i,表示月月氪金使节点 i 长出了一个新的儿子节点,权值为0,编号为当前最大编号 +1(也可以理解为,当前是第几个操作 1,新节点的编号就是多少)。
操作 2:输入格式 2 i a,表示华华上线做任务使节点 i 的子树中所有节点(即它和它的所有子孙节点)权值加 a 。
但是月月有时会检查华华有没有认真维护这棵树,会作出询问:
询问 3:输入格式3 i,华华需要给出 i 节点此时的权值。
华华当然有认真种树了,不过还是希望能写个程序以备不时之需。

输入描述:

第一行一个正整数M,接下来M行,每行先输入一个正整数O表示操作类型,再输入一个非负整数i表示操作或询问的节点编号,如果O=2,再输入一个正整数a。

输出描述:

对于每个询问3,输出一个非负整数表示询问的答案。

 

题意不说了,主要思路就是把树上的区间操作通过dfs序变成普通的区间操作,这样我们就可以直接使用树状数组或线段树来进行操作。首先我们要知道,对一棵树进行dfs,第i个节点的dfs序为DFN_i,那么以某一个节点为根的子树里面的dfs序都是连续的,即范围为(DFN_i,DFN_i+size_i-1),其中size_i以i为根节点的子树的大小。

知道上面的知识之后,我们就可以离线处理把整棵树变成一个大区间,剩下的就是区间处理。我们可以按照给定的操作顺序进行更新,但是只有在节点被加入这棵树的时候,他的权值才可以被更新,所以在它加入之前的操作都是无效的,因此我们在它加入树的时候把它当前已有的权值清零即可。

因为此题只有单点查询,所以我们可用利用树状数组可以区间更新,单点查询的特性,去维护这个区间,具体看代码。

 

#include
#include
#include
#include
#include
#define LL long long

using namespace std;


int n;
vector v[100010];
int dfn[100010];
int sz[100010];
int tree[100010];

struct query
{
    int t,id,a;
}q[400010];


void dfs(int x)
{
    dfn[x] = ++n;
    sz[x] = 1;
    for(int i=0;i

 

你可能感兴趣的:(树状数组)