牛客小白月赛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

备注

\(1\leq n,m\leq 1e6,1\leq k \leq n\)

\(1\leq u,v \leq n\)

\(1\leq a \leq n\)

\(-1e6\leq 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\n",get_ans(out[a]) - get_ans(in[a] - 1));
        }
    }
    return 0;
}

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

posted @ 2020-04-19 14:38  落水清心  阅读(149)  评论(0编辑  收藏  举报