BZOJ 4034 [HAOI2015]树上操作 树链剖分

来源:互联网 发布:淘宝客知名论坛 编辑:程序博客网 时间:2024/06/01 22:16

Description

有一棵点数为 N 的树,以点 1 为根,且树点有边权。然后有 M 个
操作,分为三种:
操作 1 :把某个节点 x 的点权增加 a 。
操作 2 :把某个节点 x 为根的子树中所有点的点权都增加 a 。
操作 3 :询问某个节点 x 到根的路径中所有点的点权和。

Input

第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 
行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, to) 。再接下来 M 行,每行分别表示一次操作。其中
第一个数表示该操作的种类( 1-3 ) ,之后接这个操作的参数( x 或者 x a ) 。

Output

对于每个询问操作,输出该询问的答案。答案之间用换行隔开。

Sample Input

5 5
1 2 3 4 5
1 2
1 4
2 3
2 5
3 3
1 2 1
3 5
2 1 2
3 3

Sample Output

6
9
13

HINT

 对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不会超过 10^6 。


题目链接


啊,终于在bzoj又找到一题水题!

此题都不需要思考,,就是树链剖分的模板题目了。

我们知道树链剖分中,为了让线段树能够维护,我们给了每个节点一个dfs序的编号。

要不下次写一篇树链剖分

所以为了更新子树,我们还需要记录一下每一个结点u的子树中dfs序最大元素的标号。

总而言之就是模板,没什么好说的。。。


哦哦,对了!

坑点就是要开long long的。


#include<bits/stdc++.h>#define ll long longusing namespace std;inline ll read(){    ll x=0,f=1;char ch=getchar();    while (ch<'0' || ch>'9'){if (ch=='-') f=-1;ch=getchar();}    while (ch>='0' && ch<='9'){x=x*10+ch-'0';ch=getchar();}    return x*f;}const intN=100005;int Ecnt,cnt,n,m;ll a[N];struct Tree{int sz,top,pre,son,tid,Max;}tree[N];struct Segment{ll mark,sum;}Seg[N<<2];struct Edge{int next,to;}E[N<<1]; int head[N];inline void add(int u,int v){E[++Ecnt].next=head[u];E[Ecnt].to=v;head[u]=Ecnt;}inline void up(int u){Seg[u].sum=Seg[u<<1].sum+Seg[u<<1|1].sum;}inline void down(int u,int l,int r){if (Seg[u].mark){int mid=(l+r)>>1;Seg[u<<1].mark+=Seg[u].mark;Seg[u<<1|1].mark+=Seg[u].mark;Seg[u<<1].sum+=Seg[u].mark*(ll)(mid-l+1);Seg[u<<1|1].sum+=Seg[u].mark*(ll)(r-mid);Seg[u].mark=(ll)0;}}void build(int x,int pre){tree[x].sz=1;tree[x].pre=pre;tree[x].son=0;int maxx=0;for (int i=head[x];i;i=E[i].next){int j=E[i].to;if (j==pre) continue;build(j,x);if (maxx<tree[j].sz){maxx=tree[j].sz;tree[x].son=j;}tree[x].sz+=tree[j].sz;}}void dfs(int x,int ancestor){tree[x].top=ancestor;tree[x].tid=tree[x].Max=++cnt;if (tree[x].son) dfs(tree[x].son,ancestor);tree[x].Max=max(tree[x].Max,tree[tree[x].son].Max);for (int i=head[x];i;i=E[i].next){int j=E[i].to;if (j==tree[x].pre || j==tree[x].son) continue;dfs(j,j);tree[x].Max=max(tree[x].Max,tree[j].Max);}}void update(int id,int l,int r,int gl,int gr,ll num){if (l>=gl && r<=gr){Seg[id].mark+=num;Seg[id].sum+=num*(ll)(r-l+1);down(id,l,r);return;}down(id,l,r);int mid=(l+r)>>1;if (gr<=mid) update(id<<1,l,mid,gl,gr,num);elseif (gl>mid)  update(id<<1|1,mid+1,r,gl,gr,num);else{update(id<<1,l,mid,gl,mid,num);update(id<<1|1,mid+1,r,mid+1,gr,num);}up(id);}ll query(int id,int l,int r,int gl,int gr){down(id,l,r);if (l>=gl && r<=gr) return Seg[id].sum;int mid=(l+r)>>1;if (gr<=mid) return query(id<<1,l,mid,gl,gr);elseif (gl>mid)  return query(id<<1|1,mid+1,r,gl,gr);elsereturn query(id<<1,l,mid,gl,mid)+query(id<<1|1,mid+1,r,mid+1,gr);up(id);}ll solve(int x){ll sum=(ll)0;while (x!=0){sum+=query(1,1,n,tree[tree[x].top].tid,tree[x].tid);x=tree[tree[x].top].pre;}return sum;}int main(){memset(Seg,0,sizeof(Seg));n=read(),m=read();for (int i=1;i<=n;i++)a[i]=read();Ecnt=0;int x,y;for (int i=1;i<n;i++){x=read(),y=read();add(x,y); add(y,x);}build(1,0);cnt=0;dfs(1,0);for (int i=1;i<=n;i++)update(1,1,n,tree[i].tid,tree[i].tid,a[i]);int opt; ll q; while (m--){opt=read();if (opt==1){x=read(),q=read();update(1,1,n,tree[x].tid,tree[x].tid,q);}elseif (opt==2){x=read(),q=read();update(1,1,n,tree[x].tid,tree[x].Max,q);}else{x=read();printf("%lld\n",solve(x));}}return 0;}