【HAOI2015】树上操作(树链剖分)

来源:互联网 发布:四年级英语辅导软件 编辑:程序博客网 时间:2024/06/16 04:04

题面

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

数据范围:
对于30%的数据,N,M<=1000。
对于50%的数据,N,M<=100000且数据随机。
对于100%的数据,N,M<=100000,且所有输入数据的绝对值都不会超过10^6。

题解

依旧是很显然的树链剖分,要用longlong存答案

#include<iostream>#include<cstdio>#include<cstdlib>#include<cstring>#include<cmath>#include<queue>#include<vector>#include<algorithm>using namespace std;#define MAX 101000#define lson (now<<1)#define rson ((now<<1)|1)inline int read(){    register int x=0,t=1;    register char ch=getchar();    while(ch!='-'&&(ch<'0'||ch>'9'))ch=getchar();    if(ch=='-'){t=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}    return x*t;}struct Line{    int v,next;}e[MAX*2];struct Node{    long long v,lazy;}c[MAX*5];int h[MAX],cnt=1,tim,V[MAX];int dfn[MAX],low[MAX],f[MAX],hson[MAX],line[MAX],size[MAX],top[MAX];int N,Q,dep[MAX];inline void Add(int u,int v){    e[cnt]=(Line){v,h[u]};    h[u]=cnt++;}void DFS1(int u,int ff){    size[u]=1;f[u]=ff;hson[u]=0;    for(int i=h[u];i;i=e[i].next)    {        int v=e[i].v;        if(v==ff)continue;        DFS1(v,u);        if(size[v]>size[hson[u]])hson[u]=v;        size[u]+=size[v];    }}void DFS2(int u,int tp){    top[u]=tp;dfn[u]=++tim;line[tim]=u;    if(hson[u])DFS2(hson[u],tp);    for(int i=h[u];i;i=e[i].next)    {        int v=e[i].v;        if(v==f[u]||v==hson[u])continue;        DFS2(v,v);    }    low[u]=tim;}void Build(int now,int l,int r){    if(l==r){c[now].v=V[line[l]];return;}    int mid=(l+r)>>1;    Build(lson,l,mid);Build(rson,mid+1,r);    c[now].v=c[lson].v+c[rson].v;}void pushdown(int now,int l,int r){    c[now].v+=1LL*(r-l+1)*c[now].lazy;    c[lson].lazy+=c[now].lazy;    c[rson].lazy+=c[now].lazy;    c[now].lazy=0;}void update(int now,int l,int r,int al,int ar,int w){    if(l==al&&r==ar){c[now].lazy+=w;return;}    int mid=(l+r)>>1;    c[now].v+=1LL*(ar-al+1)*w;    if(ar<=mid)update(lson,l,mid,al,ar,w);    else if(al>mid)update(rson,mid+1,r,al,ar,w);    else {update(lson,l,mid,al,mid,w);update(rson,mid+1,r,mid+1,ar,w);}}long long Query(int now,int l,int r,int al,int ar){    pushdown(now,l,r);    if(l==al&&r==ar)return c[now].v;    int mid=(l+r)>>1;    if(ar<=mid)return Query(lson,l,mid,al,ar);    if(al>mid)return Query(rson,mid+1,r,al,ar);    return Query(lson,l,mid,al,mid)+Query(rson,mid+1,r,mid+1,ar);}long long Answer(int u){    int v=1,tp1=top[u],tp2=top[v];    long long ans=0;    while(tp1!=tp2)    {        if(dep[tp1]<dep[tp2])        {            swap(tp1,tp2);            swap(u,v);        }        ans+=Query(1,1,N,dfn[tp1],dfn[u]);        u=f[tp1];tp1=top[u];    }    if(dep[u]<dep[v])swap(u,v);    ans+=Query(1,1,N,dfn[v],dfn[u]);    return ans;}int main(){    N=read();Q=read();    for(int i=1;i<=N;++i)V[i]=read();    for(int i=1;i<N;++i)    {        int u=read(),v=read();        Add(u,v);Add(v,u);    }    DFS1(1,0);DFS2(1,1);    Build(1,1,N);    while(Q--)    {        int kk=read();        if(kk==1)        {            int a=read(),b=read();            update(1,1,N,dfn[a],dfn[a],b);        }        if(kk==2)        {            int a=read(),b=read();            update(1,1,N,dfn[a],low[a],b);        }        if(kk==3)        {            int a=read();            printf("%lld\n",Answer(a));        }    }    return 0;}