zoukankan      html  css  js  c++  java
  • 【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
    ",Answer(a));
            }
        }
        return 0;
    }
    
  • 相关阅读:
    织梦dedecms模板中调用wordpress文章
    dede标签云(TAG)随机颜色及大小的实现方法
    将dedecms数据转换到wordpress博客程序中的方法分享
    织梦dedecms模板中友情链接标签底层模板样式调整
    织梦dede增加自定义属性四步实现
    dedecms专题分节点自由单独调用的实现方法
    DedeCMS 批量取消审核文档的实现方法
    织梦dedecms 5.1 utf-8版本英文修改方法
    织梦dedecms后台自定义字段里添加style全部都变成st<x>yle的解决教程
    Android 获取第三方软件的包名、入口Activity的类名
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7425881.html
Copyright © 2011-2022 走看看