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

 

 


 

比洛谷板子还简单。。。不解释了,应该都会吧


#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<iostream>
#define ll long long 
using namespace std;
struct node{
    ll to,next;
}e[500001];
ll head[500001],dep[500001],sum[500001],a[500001];
ll tot,num,n,m,lazy[500001],fa[500001],l[500001];
ll ch[500001],top[500001],size[500001],son[500001];
void build(int root,int l,int r)
{
    if(l==r){sum[root]=a[l];return ;}
    int mid=(l+r)>>1;
    build(root<<1,l,mid);
    build(root<<1|1,mid+1,r);
    sum[root]=sum[root<<1]+sum[root<<1|1];
    return ;
}

void push(int root,int l,int r)
{
    int mid=(l+r)>>1;
    lazy[root<<1]+=lazy[root];
    lazy[root<<1|1]+=lazy[root];
    sum[root<<1]+=lazy[root]*(mid-l+1);
    sum[root<<1|1]+=lazy[root]*(r-mid);
    lazy[root]=0;
    return ;
}

void update(int root,int left,int right,int l,int r,ll k)
{
    if(l<=left&&r>=right)
    {
    sum[root]+=k*(right-left+1);
    lazy[root]+=k;
    return;
    }
    if(left>r||right<l)return ;
    int mid=(left+right)>>1;
    if(lazy[root])push(root,left,right);
    if(mid>=l)update(root<<1,left,mid,l,r,k);
    if(mid<r) update(root<<1|1,mid+1,right,l,r,k);
    sum[root]=sum[root<<1|1]+sum[root<<1];
    return;
}

ll query(int root,int left,int right,int l,int r)
{
    if(l<=left&&r>=right)return sum[root];
    if(left>r||right<l)return 0;
    int mid=(left+right)>>1;
    if(lazy[root])push(root,left,right);
    ll a=0,b=0;
    if(mid>=l) a=query(root<<1,left,mid,l,r);
    if(mid<r)  b=query(root<<1|1,mid+1,right,l,r);
    return a+b;
}

void dfs1(int x)
{
    size[x]=1;
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(!dep[v])
        {
            dep[v]=dep[x]+1;
            fa[v]=x;
            dfs1(v);
            size[x]+=size[v];
            if(size[v]>size[son[x]])son[x]=v;
        }
        
    }
    return ;
}

void dfs2(int x,int t)
{
    l[x]=++tot;a[tot]=ch[x];top[x]=t;
    
    if(son[x])dfs2(son[x],t);
    for(int i=head[x];i;i=e[i].next)
    {
        int v=e[i].to;
        if(v!=fa[x]&&v!=son[x])
        dfs2(v,v);
    }
    return ;
}

ll cal(int x,int y)
{
    ll maxx=0;

    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(dep[fx]<dep[fy])
        {
            swap(x,y);swap(fx,fy);
        }
        maxx+=query(1,1,tot,l[fx],l[x]);
        x=fa[fx];
        fx=top[x];

    }
    if(l[x]>l[y])swap(x,y);
    maxx+=query(1,1,tot,l[x],l[y]);
    return maxx;
}

ll read()
{
    ll x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

void add(int from,int to)
{
    num++;
    e[num].to=to;
    e[num].next=head[from];
    head[from]=num;
}
int main()
{
    n=read();m=read();

    for(int i=1;i<=n;i++)
    {
        ch[i]=read();
    }
    for(int i=1;i<n;i++)
    {
        int x,y;
        x=read();y=read();
        add(x,y);add(y,x);
    }
    dep[1]=1;
    fa[1]=1;
    dfs1(1);

    dfs2(1,1);
    build(1,1,n);

    for(int i=1;i<=m;i++)
    {
        int qwq;
        qwq=read();
        if(qwq==1)
        {
            ll x,y;
            x=read();y=read();
            update(1,1,tot,l[x],l[x],y);
        }
        if(qwq==2)
        {
            ll x,y;
            x=read();y=read();
            update(1,1,tot,l[x],l[x]+size[x]-1,y);
        }

        if(qwq==3)
        {
            int x;
            x=read();
            printf("%lld\n",cal(x,1));
        }
   
    }
    return 0;
}

 

posted @ 2018-04-10 17:08  Epiphyllum_thief  阅读(173)  评论(0编辑  收藏  举报