• shoi 魔法树


    Harry Potter新学了一种魔法:可以改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法
    术。这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u]<u。初始时,这棵果
    树上的果子都被Dumbledore用魔法清除掉了,所以这个果树的每个节点都没有果子(即0个果子)不幸的是,Harry
    的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry的魔法可以
    这样描述:Add u v d,表示将节点u和v之间的路径上的所有节点的果子个数都加上d。接下来,为了方便检验Harr
    y的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:Query u,表示当前果树中,以点u
    为根的子树中,总共有多少个果子?
    Input
    第一行一个整数N(1≤N≤100000),表示果树的节点总数,节点以0,1,...,N-1标号,0一定代表根节点。
    接下来N-1行,每行两个整数a,b(0≤a接下来是一个整数Q(1≤Q≤100000),表示共有Q次操作。
    后面跟着Q行,每行是以下两种中的一种:
    1. A u v d,表示将u到v的路径上的所有节点的果子数加上d;(0≤u,v≤N-1,0<d<100000)
    2. Q u,表示询问以u为根的子树中的总果子数,注意包括u本身的。(0≤u≤N-1)
    1≤N≤100000,1≤Q≤100000
    Output
    输出询问的答案。
    Sample Input
    4
    0 1
    1 2
    2 3
    4
    A 1 3 1
    Q 0
    Q 1
    Q 2
    Sample Output
    3
    3
    2

    //记下dfs序,就知道子树的范围了 
    //对一段范围进行加值,lazy操作 
    #include <stdio.h>
    #include <iostream>
    #include <string.h>
    #include <algorithm>
    #include <stdlib.h>
    #include <math.h>
    #include <vector>
    using namespace std;
     
    typedef long long ll;
    const int N=100001;
     
    int e[N*2],nxt[N*2],head[N];
    int dep[N],fa[N],siz[N],w[N],top[N],son[N],End[N];
     
    struct A{
        ll sum,tag;
    }t[N*4];
     
    int n,C=0,edge=0;
    void add(int x,int y)
    {
        e[++edge]=y;
        nxt[edge]=head[x];
        head[x]=edge;
    }
     
    void dfs1(int x,int f,int d)
    {//求size,dep,son,fa 
        dep[x]=d;fa[x]=f;siz[x]=1;
        int i,tp=0;
        for(i=head[x];i;i=nxt[i])
            if(e[i]!=fa[x])
            {
                dfs1(e[i],x,d+1);
                siz[x]+=siz[e[i]];
                if(siz[e[i]]>tp){tp=siz[e[i]];son[x]=e[i];}
            }
    }
     
    void dfs2(int x,int tp)
    {//求dfs序,链的顶端节点 
        w[x]=++C;
    	top[x]=tp;
        if(son[x]) 
    	dfs2(son[x],top[x]);
        for(int i=head[x];i;i=nxt[i])
            if(e[i]!=son[x]&&e[i]!=fa[x])
                dfs2(e[i],e[i]);
        End[x]=C;//x所在子树的最大dfs序 
    }
     
    void build(int x,int l,int r)
    {//建立线段树 
        t[x].tag=t[x].sum=0;
        if(l==r) return;
        int M=l+r>>1;
        build(x<<1,l,M);
        build(x<<1|1,M+1,r);
    }
     
    void pushdown(int x,int l,int r)
    {//在线段树中下传标记 
        if(t[x].tag)
        {
            t[x<<1].tag+=t[x].tag;
            t[x<<1|1].tag+=t[x].tag;
            int M=l+r>>1;
            t[x<<1].sum+=(M-l+1)*t[x].tag;
            t[x<<1|1].sum+=(r-M)*t[x].tag;
            t[x].tag=0;
        }
    }
     
    void update(int x,int l,int r,int ql,int qr,int v)
    {//在线段树中更新[ql,qr]节点权值加v 
        if(ql<=l&&qr>=r)
         {
            t[x].sum+=(r-l+1)*v;
            t[x].tag+=v;
            return;
         }
        pushdown(x,l,r);
        int M=l+r>>1;
        if(ql<=M) 
    	   update(x<<1,l,M,ql,qr,v);
        if(qr>M) 
    	   update(x<<1|1,M+1,r,ql,qr,v);
        t[x].sum=t[x<<1].sum+t[x<<1|1].sum;
    }
     
    ll query(int x,int l,int r,int ql,int qr)
    {//在线段树中查询[ql,qr]的权值和 
        if(ql<=l&&qr>=r) return t[x].sum;
        pushdown(x,l,r);
        int M=l+r>>1;ll sum=0;
        if(ql<=M) sum+=query(x<<1,l,M,ql,qr);
        if(qr>M) sum+=query(x<<1|1,M+1,r,ql,qr);
        return sum;
    }
     
    void upd(int x,int y,int z)
    {//修改操作,见课件 
        int f1=top[x],f2=top[y],tmp;
        while(f1!=f2)
        {
            if(dep[f1]<dep[f2])
            {
                tmp=f1;f1=f2;f2=tmp;
                tmp=x;x=y;y=tmp;
            }
            update(1,1,n,w[f1],w[x],z);
            x=fa[f1];
    		f1=top[x];
        }
        if(dep[x]<dep[y]){tmp=x;x=y;y=tmp;}
        update(1,1,n,w[y],w[x],z);  //注意这一句,本题是对点权进行操作 
    }
     
    int main()
    {   
        int i,x,y,m,z;char c;
        scanf("%d",&n);
        for(i=1;i<n;i++)
        {
            scanf("%d %d",&x,&y);x++;y++;
            add(x,y);
    		add(y,x);
        }
        dfs1(1,-1,1);
        dfs2(1,1);
        build(1,1,n);
        scanf("%d",&m);
        for(i=1;i<=m;i++)
        {
            scanf("
    %c",&c);
            if(c=='A')
            {
                scanf("%d %d %d",&x,&y,&z);x++;y++;
                upd(x,y,z);
            }
            else
            {
                scanf("%d",&x);//统计以x为根的子树的权值 
    			x++;
                printf("%lld
    ",query(1,1,n,w[x],End[x]));
            }
        }
        return 0;
    }
    

      

  • 相关阅读:
    强连通分量
    mysql安装图解 mysql图文安装教程(详细说明)
    MeshCombineUtility.cs method `GetTriangleStrip' of type `UnityEngine.Mesh' could be found
    socket网络编程之一:客户端和服务器端接口函数
    unity3D——登录界面
    Ionic学习注意事项01
    这里我将分享我学到的几种ionic登陆界面
    关于ionic基础教程的学习网址
    Windows下配置Git
    Cocos网络篇[3.2](3) ——Socket连接(1)
  • 原文地址:https://www.cnblogs.com/cutemush/p/11858018.html
Copyright © 2020-2023  润新知