dfs序模板题

82 阅读2分钟

链接:ac.nowcoder.com/acm/problem…
来源:牛客网

题目描述

已知有 n 个节点,有 n−1 条边,形成一个树的结构。

给定一个根节点 k,每个节点都有一个权值,节点i的权值为 vi​。

给 m 个操作,操作有两种类型:

1 a x :表示将节点 a 的权值加上 x

2 a :表示求 a节点的子树上所有节点的和(包括 a 节点本身)

输入描述:

第一行给出三个正整数 n,m,k,表示树的节点数、操作次数、和这棵树的根节点.

第二行给出 n 个正整数,第 i个正整数表示第 i 个节点的权值 vali​

下面 n−1 行每行两个正整数 u,v,表示边的两个端点

接下来 m 行,每行给出一个操作

输出描述:

对于每个类型为 2 的操作,输出一行一个正整数,表示以 a 为根的子树的所有节点的权值和

思路:因为题目要求我们做到单点修改, 区间求和的一个操作
显然树状数组能够满足要求

代码:

#include <bits/stdc++.h>

using namespace std;
#define int long long
const int N = 1e6 + 10;
int n,m,k,cnt,tot;
int l[N],r[N],a[N];
vector<int>edg[N];
template<class T>
struct NOW{
    T c[N];
    void init(int x)
    {
        for(int i = 1;i <= x;i ++)
            c[i] = 0;
    }
    
    void modify(int x,int u)
    {
        for(;x <= n;x += (x&-x))
            c[x] += u;
    }
    
    T query(int x)
    {
        int ans = 0;
        for(;x;x -= (x&-x))
            ans += c[x];
        return ans;
    }
};

NOW <int> c;

void dfs(int x,int u)
{
    l[x] = ++cnt;
    for(int i = 0;i < edg[x].size();i ++)
    {
        if(edg[x][i] == u)
            continue;
        dfs(edg[x][i],x);
    }
    r[x] = cnt;
}
void solve(){
    scanf("%d%d%d",&n,&m,&k);
    c.init(n);
    for(int i = 1;i <= n;i ++)
    {
        scanf("%d",&a[i]);
    }
    
    for(int i = 1;i < n;i ++)
    {
        int x,y;
        scanf("%d %d",&x,&y);
        edg[x].push_back(y);
        edg[y].push_back(x);
    }
    dfs(k,0);
    for(int i = 1;i <= n;i ++)
    {
         c.modify(l[i],a[i]);
    }
    while(m--)
    {
        int ty;
        scanf("%d",&ty);
        if(ty == 1)
        {
            int x,y;
            scanf("%d %d",&x,&y);
            c.modify(l[x],y);
        }
        else
        {
            int x;
            scanf("%d",&x);
            int num = c.query(r[x]) - c.query(l[x]-1);
            printf("%d\n",num);
        }
    }
}
signed main()
{
    int _ = 1;
    while(_--)
    solve();
}