牛客小白月赛24—I.求和

牛客小白月赛24—I.求和

题目描述

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

给定一个根节点(k),每个节点都有一个权值,节点(i)的权值为(v_i)

(m)个操作,操作有两种类型:

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

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

输入描述

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

第二行给出(n)个正整数,第(i)个正整数表示第(i)个节点的权值(val_i)

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

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

输出描述

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

样例输入

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

样例输出

13
27

备注

(1leq n,mleq 1e6,1leq k leq n)

(1leq u,v leq n)

(1leq a leq n)

(-1e6leq val_i,x leq 1e6)

建议使用scanf读入

思路

DFS序加树状数组或者线段树维护前缀和

关于DFS序见:https://www.cnblogs.com/LeafLove/p/12730685.html

Code

#include <bits/stdc++.h>
#define CSE(x,y) memset(x,y,sizeof(x))
#define INF 0x3f3f3f3f
#define FAST ios::sync_with_stdio(false);cin.tie(0);
using namespace std;

typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll , ll> pll;

const int maxn = 2000111;
//graph_describe
int v[maxn],u[maxn],first[maxn],nxt[maxn],n,m,k,cnt;
ll val[maxn];
//dfs_order
int in[maxn],out[maxn],order;
//Tree_array
ll sum[maxn];

void add(int a,int b) {
	cnt++;
    u[cnt] = a; v[cnt] = b; nxt[cnt] = first[u[cnt]]; first[u[cnt]] = cnt;
    return;
}

void dfs(int be,int fa) {
    in[be] = ++order;
    for(int i=first[be];i!=-1;i=nxt[i]) {
        if(v[i] != fa) {
            dfs(v[i],be);
        }
    }
    out[be] = order;
    return;
}

int lowbit(int x) { return x & (-x);}
ll get_ans(int x) {
	ll ans = 0; while(x) {ans += sum[x];x -= lowbit(x);}
    return ans;
}
void update(int x,ll w) {
    while(x<=n) { sum[x] += w; x += lowbit(x);}
    return;
}

int main()
{
#ifndef ONLINE_JUDGE
    freopen("in.in","r",stdin);
#endif
    scanf("%d%d%d",&n,&m,&k);
    for(int i=1;i<=n;i++) {
        scanf("%lld", &val[i]);
    }
    for(int i=1;i<=n;i++) first[i] = -1;
	for(int i=1;i<n;i++) {
	    int a,b;
	    scanf("%d%d",&a,&b);
	    add(a,b); add(b,a);
	}
    dfs(k,-1);
    for(int i=1; i<=n; i++) {
        update(in[i],val[i]);
    }
    while(m--){
        int d,a;
        scanf("%d%d",&d,&a);
        if(d==1) {
            ll x;
            scanf("%lld",&x);
            update(in[a],x);
        }
        else
        {
            printf("%lld
",get_ans(out[a]) - get_ans(in[a] - 1));
        }
    }
    return 0;
}

第一次接触这种题时,真的是被这个做法深深吸引了

原文地址:https://www.cnblogs.com/LeafLove/p/12731495.html