• bzoj4034


    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

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

    预处理树的前序和后序遍历的编号

    按编号用两棵线段树分别维护区间和

    子树的编号连续可以直接修改

    结点到根的路径和可以用前序和后序的信息相减得到

    时间复杂度O(nlogn)

    #include<cstdio>
    #include<cstring>
    #define N 100005
    typedef long long lint;
    int n,m,a,b,o;
    int v[N];
    int es[N*3],enx[N*3],ep=N;
    void addedge(int a,int b){
        es[ep]=b;
        enx[ep]=enx[a];
        enx[a]=ep++;
        es[ep]=a;
        enx[ep]=enx[b];
        enx[b]=ep++;
    }
    struct sgt{
        lint s[262144];
        lint a[262144];
        sgt(){
            memset(s,0,sizeof(s));
            memset(a,0,sizeof(a));
        }
        void down(int w,int l,int r){
            if(l<r){
                a[w+w]+=a[w];
                a[w+w+1]+=a[w];
                int x=(r+1-l)>>1;
                s[w+w]+=a[w]*x;
                s[w+w+1]+=a[w]*x;
            }
            a[w]=0;
        }
        void add(int l,int r,lint x,int w=1,int L=1,int R=131072){
            int M=L+R>>1;
            if(a[w])down(w,L,R);
            if(l==L&&r==R){
                a[w]+=x;
                s[w]+=x*(R+1-L);
                return;
            }
            if(r<=M)add(l,r,x,w+w,L,M);
            else if(l>M)add(l,r,x,w+w+1,M+1,R);
            else add(l,M,x,w+w,L,M),add(M+1,r,x,w+w+1,M+1,R);
            s[w]=s[w+w]+s[w+w+1];
        }
        lint get(int l,int r,int w=1,int L=1,int R=131072){
            int M=L+R>>1;
            if(a[w])down(w,L,R);
            if(l==L&&r==R)return s[w];
            if(r<=M)return get(l,r,w+w,L,M);
            else if(l>M)return get(l,r,w+w+1,M+1,R);
            else return get(l,M,w+w,L,M)+get(M+1,r,w+w+1,M+1,R);
        }
    }t1,t2;
    int i1[N],i2[N],m1[N],m2[N],p1=1,p2=2;
    void f(int w,int pa){
        i1[w]=p1++;
        m2[w]=p2;
        for(int i=enx[w];i;i=enx[i]){
            int u=es[i];
            if(u!=pa)f(u,w);
        }
        m1[w]=p1-1;
        i2[w]=p2++;
    }
    int main(){
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",v+i);
        for(int i=1;i<n;i++){
            scanf("%d%d",&a,&b);
            addedge(a,b);
        }
        f(1,0);
        for(int i=1;i<=n;i++){
            t1.add(i1[i],i1[i],v[i]);
            t2.add(i2[i],i2[i],v[i]);
        }
        while(m--){
            scanf("%d",&o);
            if(o==1){
                scanf("%d%d",&a,&b);
                t1.add(i1[a],i1[a],b);
                t2.add(i2[a],i2[a],b);
            }else if(o==2){
                scanf("%d%d",&a,&b);
                t1.add(i1[a],m1[a],b);
                t2.add(m2[a],i2[a],b);
            }else{
                scanf("%d",&a);
                printf("%lld
    ",t1.get(1,i1[a])-t2.get(1,m2[a]-1));
            }
        }
        return 0;
    }
  • 相关阅读:
    TypeScript系列
    常用软件工具
    How to change Eclipse loading image
    【奥斯卡理财星体系 第五章】丨手把手教你从零开始搭建资产配置
    【奥斯卡理财星体系 第四章】丨你该如何选择适合的理财工具
    【奥斯卡理财星体系 第三章】丨你适合追求什么样的收益率
    ASP.NET Core使用Elasticsearch记录API请求响应日志实战演练
    C# Quartz.NET实现动态改变作业调度周期
    openssl 生成pfx
    netcore进程内(InProcess)托管和进程外(out-of-Process)托管
  • 原文地址:https://www.cnblogs.com/ccz181078/p/5171235.html
Copyright © 2020-2023  润新知