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

题面

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;
}
posted @ 2017-08-24 23:38  小蒟蒻yyb  阅读(249)  评论(0编辑  收藏  举报