NC204871. 求和
描述
已知有 个节点,有 条边,形成一个树的结构。
给定一个根节点 ,每个节点都有一个权值,节点i的权值为 。
给 个操作,操作有两种类型:
1 a x :表示将节点 的权值加上
2 a :表示求 节点的子树上所有节点的和(包括 节点本身)
输入描述
第一行给出三个正整数 ,表示树的节点数、操作次数、和这棵树的根节点.
第二行给出 个正整数,第 个正整数表示第 个节点的权值
下面 行每行两个正整数 ,表示边的两个端点
接下来 行,每行给出一个操作
输出描述
对于每个类型为 2 的操作,输出一行一个正整数,表示以 为根的子树的所有节点的权值和
示例1
输入:
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
C++11(clang++ 3.9) 解法, 执行用时: 1638ms, 内存消耗: 116552K, 提交时间: 2020-04-18 19:32:42
#include<bits/stdc++.h> using namespace std; int n,m,k,tot=0,in[1000005],out[1000005],a[1000005]; long long S[1000005]={0}; int lowbit(int x) { return x&(-x); } void update(int i,int x) { while(i<=n)S[i]+=x,i+=lowbit(i); } long long getsum(int i) { long long s=0; while(i)s+=S[i],i-=lowbit(i); return s; } vector<int>R[1000005]; void DFS(int x,int fa) { int i,j; in[x]=++tot,update(tot,a[x]); for(i=0;i<R[x].size();i++) { j=R[x][i]; if(j!=fa)DFS(j,x); } out[x]=tot; } int main() { int i,x,y,op; scanf("%d%d%d",&n,&m,&k); for(i=1;i<=n;i++)scanf("%d",&a[i]); for(i=0;i<n-1;i++) { scanf("%d%d",&x,&y); R[x].push_back(y),R[y].push_back(x); } DFS(k,0); while(m--) { scanf("%d%d",&op,&x); if(op==1)scanf("%d",&y),update(in[x],y); else printf("%lld\n",getsum(out[x])-getsum(in[x]-1)); } return 0; }
C++14(g++5.4) 解法, 执行用时: 1500ms, 内存消耗: 112516K, 提交时间: 2020-04-19 11:28:40
#include<bits/stdc++.h> using namespace std; const int N=1e6+5; int tr[N],n,m,k,a[N],in[N],out[N],tot; typedef long long ll; #define lowbit(x) (x&-x) vector<int>e[N]; void upd(int i,int x){ while(i<=n){ tr[i]+=x; i+=lowbit(i); } } ll sum(int i){ ll sum=0; while(i) sum+=tr[i],i-=lowbit(i); return sum; } void dfs(int u,int fa){ in[u]=++tot,upd(tot,a[u]); for(auto v:e[u]){ if(v!=fa) dfs(v,u); } out[u]=tot; } int main(){ scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1,u,v;i<n;i++){ scanf("%d%d",&u,&v); e[u].push_back(v),e[v].push_back(u); } dfs(k,0); while(m--){ int op,a,x; scanf("%d%d",&op,&a); if(op==1) scanf("%d",&x),upd(in[a],x); else printf("%lld\n",sum(out[a])-sum(in[a]-1)); } return 0; }