P3178 [HAOI2015]树上操作
题目描述
有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个操作,分为三种:操作 1 :把某个节点 x 的点权增加 a 。操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。操作 3 :询问某个节点 x 到根的路径中所有点的点权和。
输入输出格式
输入格式:
第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行两个正整数 from, to , 表示该树中存在一条边 (from, to) 。再接下来 M 行,每行分别表示一次操作。其中第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。
输出格式:
对于每个询问操作,输出该询问的答案。答案之间用换行隔开。
输入输出样例
说明
对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不
会超过 10^6 。
// luogu-judger-enable-o2 #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int N=1e5+5; int n,m; int w[N]; int opt,x,a; int head[N],num_edge; struct Edge { int v,nxt; }edge[N<<1]; struct Node { int fa,son; int size; int top; int s,t; int dep; }node[N]; struct TREE { TREE *lson,*rson; int l,r,mid; long long sum,addval; }tree[N<<2]; typedef TREE* Tree; Tree now_node=tree,Root; inline int read() { char c=getchar();int num=0,f=1; for(;!isdigit(c);c=getchar()) f=c=='-'?-1:f; for(;isdigit(c);c=getchar()) num=num*10+c-'0'; return num*f; } inline void add_edge(int u,int v) { edge[++num_edge].v=v; edge[num_edge].nxt=head[u]; head[u]=num_edge; } void dfs1(int u) { node[u].size=1; for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==node[u].fa) continue; node[v].fa=u; node[v].dep=node[u].dep+1; dfs1(v); node[u].size+=node[v].size; if(node[v].size>node[node[u].son].size) node[u].son=v; } } int bound; void dfs2(int u,int top) { node[u].s=++bound; node[u].top=top; if(node[u].son) { dfs2(node[u].son,top); for(int i=head[u],v;i;i=edge[i].nxt) { v=edge[i].v; if(v==node[u].fa||v==node[u].son) continue; dfs2(v,v); } } node[u].t=bound; } void build(Tree &root,int l,int r) { root=++now_node; root->l=l,root->r=r,root->mid=l+r>>1; if(l==r) return; build(root->lson,l,root->mid); build(root->rson,root->mid+1,r); } inline void pushdown(Tree root) { if(root->addval) { root->lson->addval+=root->addval; root->rson->addval+=root->addval; root->lson->sum+=(root->lson->r-root->lson->l+1)*root->addval; root->rson->sum+=(root->rson->r-root->rson->l+1)*root->addval; root->addval=0; } } void update(const Tree &root,int l,int r,int k) { if(l==root->l&&root->r==r) { root->sum+=(r-l+1)*1LL*k; root->addval+=k; return; } pushdown(root); if(r<=root->mid) update(root->lson,l,r,k); else if(l>root->mid) update(root->rson,l,r,k); else { update(root->lson,l,root->mid,k); update(root->rson,root->mid+1,r,k); } root->sum=root->lson->sum+root->rson->sum; } long long query(Tree root,int l,int r) { if(l<=root->l&&root->r<=r) return root->sum; pushdown(root); if(r<=root->mid) return query(root->lson,l,r); else if(l>root->mid) return query(root->rson,l,r); else return query(root->lson,l,root->mid)+query(root->rson,root->mid+1,r); } inline long long Query(int x) { int fx=node[x].top; long long ans=0; while(fx!=1) { ans+=query(Root,node[fx].s,node[x].s); x=node[fx].fa; fx=node[x].top; } return ans+query(Root,node[1].s,node[x].s); } int main() { n=read(),m=read(); for(int i=1;i<=n;++i) w[i]=read(); for(int i=1,u,v;i<n;++i) { u=read(),v=read(); add_edge(u,v); add_edge(v,u); } dfs1(1); dfs2(1,1); build(Root,1,n); for(int i=1;i<=n;++i) update(Root,node[i].s,node[i].s,w[i]); while(m--) { opt=read(); if(opt==1) { x=read(),a=read(); update(Root,node[x].s,node[x].s,a); } else if(opt==2) { x=read(),a=read(); update(Root,node[x].s,node[x].t,a); } else { x=read(); printf("%lld\n",Query(x)); } } return 0; }