洛谷 P3178 [HAOI2015]树上操作

题目描述

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

输入输出格式

输入格式:

 

第一行包含两个整数 N, M 。表示点数和操作数。接下来一行 N 个整数,表示树中节点的初始权值。接下来 N-1 行每行三个正整数 fr, to , 表示该树中存在一条边 (fr, 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 。

 

树剖裸题

俩小时。。卧槽!

别用scanf读long long 的负数!

别用scanf读long long 的负数!

别用scanf读long long 的负数!

屠龙宝刀点击就送

#include <iostream>
#include <ctype.h>
#include <cstdio>
#define N 200005
#define M 100005
using namespace std;
typedef long long LL;
struct Tree
{
    LL l,r,dis,lazy;
}tr[N<<2|1];
struct node
{
    LL next,to;
}edge[N<<1];
LL dfn[M],dis[M],n,m,root,p,top[M],belong[M],tim,head[M],cnt,fa[M],dep[M],size[M];
void add(LL u,LL v)
{
    edge[++cnt].next=head[u];
    edge[cnt].to=v;
    head[u]=cnt;
}
void dfs1(LL now)
{
    dep[now]=dep[fa[now]]+1;
    size[now]=1;
    for(LL i=head[now];i;i=edge[i].next)
    {
        LL v=edge[i].to;
        if(fa[now]!=v)
        {
            fa[v]=now;
            dfs1(v);
            size[now]+=size[v];
        }
    }
}
void dfs2(LL now)
{
    belong[now]=++tim;
    dfn[tim]=now;
    LL t=0;
    if(!top[now]) top[now]=now;
    for(LL i=head[now];i;i=edge[i].next)
    {
        LL v=edge[i].to;
        if(fa[now]!=v&&size[t]<size[v]) t=v;
    }
    if(t) top[t]=top[now],dfs2(t);
    for(LL i=head[now];i;i=edge[i].next)
    {
        LL v=edge[i].to;
        if(fa[now]!=v&&v!=t) dfs2(v);
    }
}
void up(LL k) {tr[k].dis=tr[k<<1].dis+tr[k<<1|1].dis ;} 
void build(LL k,LL l,LL r)
{
    tr[k].l=l;
    tr[k].r=r;
    if(l==r)
    {
        tr[k].dis=dis[dfn[l]];
        return;
    }
    LL mid=(l+r)>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    up(k); 
}
void swap(LL &a,LL &b)
{
    LL tmp=b;
    b=a;
    a=tmp;
}
void pushdown(LL k)
{
    if(tr[k].l==tr[k].r) return;
    tr[k<<1].lazy+=tr[k].lazy;
    tr[k<<1|1].lazy+=tr[k].lazy;
    tr[k<<1].dis=tr[k<<1].dis+(tr[k<<1].r-tr[k<<1].l+1)*tr[k].lazy;
    tr[k<<1|1].dis=tr[k<<1|1].dis+(tr[k<<1|1].r-tr[k<<1|1].l+1)*tr[k].lazy;
    tr[k].lazy=0;
}
void Tree_change(LL k,LL l,LL r,LL z)
{
    if(tr[k].l==l&&tr[k].r==r)
    {
        tr[k].lazy+=z;
        tr[k].dis=tr[k].dis+(r-l+1)*z;
        return;
    }
    if(tr[k].lazy) pushdown(k);
    LL mid=(tr[k].l+tr[k].r)>>1;
    if(l>mid) Tree_change(k<<1|1,l,r,z);
    else if(r<=mid) Tree_change(k<<1,l,r,z);
    else Tree_change(k<<1,l,mid,z),Tree_change(k<<1|1,mid+1,r,z);
    up(k);
}
LL Tree_query(LL k,LL l,LL r)
{
    if(tr[k].lazy) pushdown(k);
    if(tr[k].l==l&&tr[k].r==r)
        return tr[k].dis;
    LL mid=(tr[k].l+tr[k].r)>>1;
    if(l>mid) return Tree_query(k<<1|1,l,r);
    else if(r<=mid) return Tree_query(k<<1,l,r);
    else return (Tree_query(k<<1,l,mid)+Tree_query(k<<1|1,mid+1,r));
    up(k); 
}
void Chain_change(LL x,LL y,LL z)
{
    for(;top[x]!=top[y];x=fa[top[x]])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        Tree_change(1,belong[top[x]],belong[x],z);
    }
    if(dep[x]<dep[y]) swap(x,y);
    Tree_change(1,belong[y],belong[x],z);
}
LL Chain_query(LL x,LL y)
{
    LL ans=0;
    for(;top[x]!=top[y];x=fa[top[x]])
    {
        if(dep[top[x]]<dep[top[y]]) swap(x,y);
        ans=(ans+Tree_query(1,belong[top[x]],belong[x])); 
    }
    if(dep[x]<dep[y]) swap(x,y);
    ans=(ans+Tree_query(1,belong[y],belong[x]));
    return ans;
}
void read(LL &x)
{
    x=0;bool f=0;
    char ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=1;ch=getchar();}
    while(isdigit(ch)) {x=x*10+ch-'0';ch=getchar();}
    x=f?-x:x; 
}
int main()
{
    read(n);read(m);
    for(LL i=1;i<=n;i++) read(dis[i]);
    for(LL x,y,i=1;i<n;i++)
    {
        read(x);read(y);
        add(x,y);
        add(y,x);
    }
    dfs1(1);
    dfs2(1);
    build(1,1,n);
    for(LL opt,x,a;m--;)
    {
        read(opt);
        if(opt==1)
        {
            read(x);read(a);
            Tree_change(1,belong[x],belong[x],a);
        }
        else if(opt==2)
        {
            read(x);read(a);
            Tree_change(1,belong[x],belong[x]+size[x]-1,a);
        }
        else if(opt==3)
        {
            read(x);
            cout<<Chain_query(1,x)<<endl;
        }
    }
    return 0;
}

 

posted @ 2017-07-17 15:24  杀猪状元  阅读(143)  评论(0编辑  收藏  举报