[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 ) 。

输出格式:

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

输入输出样例

输入样例#1:

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

输出样例#1:

6 9 13 对于 100% 的数据, N,M<=100000 ,且所有输入数据的绝对值都不

会超过 10^6 。

solution

树链剖分裸题没什么好说的。。。

对于操作1,线段树单点修改

操作2,区间修改

操作3,相当于求节点1,到节点x这条链上的和。

然而求这么简单一道题,我还提交了8遍。。。

主要是细节:

1.把建树的1打成了l。

2.把查询中的这个

 if(dep[tx]>dep[ty])
        {
            swap(x,y);
            swap(tx,ty);
        }

写成了这样

 if(dep[x]>dep[y])
        {
            swap(x,y);
            swap(tx,ty);
        }

3.把一个+=写成了=

4.单点修改没有管懒标记。

代码

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100000 + 10;
inline int read()
{
    char ch;
    int fl=1;
    int xx=0;
    do{
      ch= getchar();
      if(ch=='-')
        fl=-1;
    }while(ch<'0'||ch>'9');
    do{
        xx=(xx<<3)+(xx<<1)+ch-'0';
        ch=getchar();
    }while(ch>='0'&&ch<='9');
    return xx*fl;
}
int n,m;
int a[MAXN];
struct node
{
    int to;
    int next;
};node g[MAXN*2];
int fa[MAXN],head[MAXN],dep[MAXN],tot[MAXN],son[MAXN],cnt=0;
inline void addedge(int x,int y){
    ++cnt;g[cnt].to=y;g[cnt].next=head[x];head[x]=cnt;return;
}
inline void dfs(int x)
{
    tot[x]=1,son[x]=0;
    for(int i=head[x];i>0;i=g[i].next)
    {
        int v=g[i].to;
        if(v!=fa[x])
        {
            dep[v]=dep[x]+1;
            fa[v]=x;
            dfs(v);
            if(tot[v]>tot[son[x]]) son[x]=v;
            tot[x]+=tot[v];
        }
    }
    return;
}
int num[MAXN],top[MAXN],z=0;
inline void dfs2(int now,int t)
{
    top[now]=t;++z;num[now]=z;
    if(son[now]) dfs2(son[now],t);
    for(int i=head[now];i>0;i=g[i].next)
    {
        int v=g[i].to;
        if(v!=son[now]&&v!=fa[now])
        dfs2(v,v);
    }
}
struct TREE
{
    int l;
    int r;
    long long sum;
    inline int mid(){
        return    (l+r)>>1;
    }
}tree[MAXN*4];
long long add[MAXN*4];
#define lc o<<1
#define rc o<<1|1
inline void build(int o,int l,int r)
{
    tree[o].l=l;tree[o].r=r;
    int  mid=tree[o].mid();
    if(l==r) {
        tree[o].sum=0;
        return;
    }
    else
    {
        build(lc,l,mid);
        build(rc,mid+1,r);
        tree[o].sum=tree[lc].sum+tree[rc].sum;
    } 
}

inline void pushup(int o)
{
    add[lc]+=add[o];
    add[rc]+=add[o];
    tree[lc].sum+=(tree[lc].r-tree[lc].l+1)*add[o];
    tree[rc].sum+=(tree[rc].r-tree[rc].l+1)*add[o];
    add[o]=0;
}

inline void change(int o,int x,int y)
{
    int l=tree[o].l,r=tree[o].r;
    int mid=tree[o].mid();
    if(l==r)
    {
        tree[o].sum+=y;
        return;
    }
    else
    {
        pushup(o);
        if(x>=mid+1) change(rc,x,y);
        else change(lc,x,y);
        tree[o].sum=tree[lc].sum+tree[rc].sum;
    }
}

inline void change2(int o,int x,int y,long long z)
{
    int l=tree[o].l,r=tree[o].r;
    if(x<=l&&y>=r)
    {
        add[o]+=z;
        tree[o].sum+=(tree[o].r-tree[o].l+1)*z;
        return;
    }
    else if(l>y||x>r) return ;
    else
    {
        if(add[o])
        pushup(o);
        change2(lc,x,y,z);
        change2(rc,x,y,z);
        tree[o].sum=tree[lc].sum+tree[rc].sum;
        return;
    }    
} 
inline long long query(int o,int x,int y)
{
    int l=tree[o].l,r=tree[o].r;
    if(x<=l&&y>=r)
    {
        return tree[o].sum;
    }
    else if(l>y||x>r) return 0;
    else
    {
        if(add[o])
        pushup(o);
        return query(lc,x,y)+query(rc,x,y);
    }        
} 
inline long long query_sum(int x,int y)
{
    int tx=top[x],ty=top[y];
    long long ans=0;
    while(tx!=ty)
    {
        if(dep[tx]>dep[ty])
        {
            swap(x,y);
            swap(tx,ty);
        }
        ans+=query(1,num[ty],num[y]);
        y=fa[ty];ty=top[y];
    }
    if(dep[x]>dep[y])
    {
        swap(x,y);
    }
    ans+=query(1,num[x],num[y]);
    return ans;
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++) a[i]=read(),head[i]=-1;
    for(int i=1;i<n;i++)
    {
        int x,y;
        x=read();
        y=read();
        addedge(x,y);
        addedge(y,x);
    }
    fa[1]=0;dep[1]=1;dfs(1);
    dfs2(1,1);
    build(1,1,z);
    for(int i=1;i<=n;i++) 
    change(1,num[i],a[i]);
    for(int i=1;i<=m;i++)
    {
        long long op,x,y;
        op=read();
        if(op==1)
        {
            x=read(),y=read();
            change(1,num[x],y);
        }
        if(op==2)
        {
            x=read();y=read();
            change2(1,num[x],num[x]+tot[x]-1,y);
        }
        if(op==3)
        {
            x=read();
            printf("%lld
",query_sum(1,x));
        }
    }
        return 0;
}