• 洛谷 P3833 [SHOI2012]魔法树


    题目背景

    SHOI2012 D2T3

    题目描述

    Harry Potter 新学了一种魔法:可以让改变树上的果子个数。满心欢喜的他找到了一个巨大的果树,来试验他的新法术。

    这棵果树共有N个节点,其中节点0是根节点,每个节点u的父亲记为fa[u],保证有fa[u] < u。初始时,这棵果树上的果子都被 Dumbledore 用魔法清除掉了,所以这个果树的每个节点上都没有果子(即0个果子)。

    不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:

    Add u v d

    表示将点u和v之间的路径上的所有节点的果子个数都加上d。

    接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:

    Query u

    表示当前果树中,以点u为根的子树中,总共有多少个果子?

    输入输出格式

    输入格式:

    第一行一个正整数N (1 ≤ N ≤ 100000),表示果树的节点总数,节点以0,1,…,N − 1标号,0一定代表根节点。

    接下来N − 1行,每行两个整数a,b (0 ≤ a < b < N),表示a是b的父亲。

    接下来是一个正整数Q(1 ≤ ? ≤ 100000),表示共有Q次操作。

    后面跟着Q行,每行是以下两种中的一种:

    1. A u v d,表示将u到v的路径上的所有节点的果子数加上d;0 ≤ u,v <N,0 < d < 100000

    2. Q u,表示询问以u为根的子树中的总果子数,注意是包括u本身的。

    输出格式:

    对于所有的Query操作,依次输出询问的答案,每行一个。答案可能会超过2^32 ,但不会超过10^15 。

    输入输出样例

    输入样例#1: 复制
    4
    0 1
    1 2
    2 3
    4
    A 1 3 1
    Q 0
    Q 1
    Q 2
    输出样例#1: 复制
    3
    3
    2

    题解:
      树链剖分的板子好久没打了,写一写。
     
    代码:
      
    // luogu-judger-enable-o2
    // luogu-judger-enable-o2
    #include <cstdio>
    #include <iostream>
    #include <algorithm>
    #include <cstring>
    #include <cmath>
    #include <iostream>
    #define MAXN 400100
    #define ll long long
    using namespace std;
    struct edge{
        int first;
        int next;
        int to;
    }a[MAXN*2];
    struct tree{
        int l,r;ll sum,lz; 
    }tr[MAXN*4];
    
    int num,n;
    int dep[MAXN],sz[MAXN],id[MAXN],son[MAXN],tp[MAXN],dfn[MAXN],las[MAXN],fa[MAXN];
    
    void addedge(int from,int to){
        a[++num].to=to;
        a[num].next=a[from].first;
        a[from].first=num;
    }
    
    void dfs1(int now,int f){
        fa[now]=f,sz[now]=1,dep[now]=dep[f]+1;
        for(int i=a[now].first;i;i=a[i].next){
            int to=a[i].to;
            if(to==f) continue;
            dfs1(to,now);
            sz[now]+=sz[to];
            if(sz[son[now]]<sz[to]) son[now]=to;
        }
    }
    
    void dfs2(int now,int top){
        dfn[now]=++num;
        tp[now]=top;
        if(son[now]) dfs2(son[now],top);
        for(int i=a[now].first;i;i=a[i].next){
            int to=a[i].to;if(to==fa[now]||to==son[now]) continue;
            dfs2(to,to);
        }
        las[now]=num;
    }
    
    void pushdown(int xv){
        int ls=2*xv,rs=2*xv+1;
        if(tr[xv].lz){
            tr[ls].sum+=(tr[ls].r-tr[ls].l+1)*tr[xv].lz;
            tr[rs].sum+=(tr[rs].r-tr[rs].l+1)*tr[xv].lz;
            tr[ls].lz+=tr[xv].lz,tr[rs].lz+=tr[xv].lz;
            tr[xv].lz=0;
        }
    }
    
    void pushup(int xv){
        tr[xv].sum=tr[xv*2].sum+tr[xv*2+1].sum;
    }
    
    void build(int xv,int l,int r){
        if(l==r){
            tr[xv].l=l,tr[xv].r=r,tr[xv].sum=0,tr[xv].lz=0;
            return;
        }
        tr[xv].l=l,tr[xv].r=r,tr[xv].sum=0,tr[xv].lz=0;
        int mid=(l+r)/2;
        build(xv*2,l,mid),build(xv*2+1,mid+1,r);
    }
    
    void modify(int xv,int l,int r,int z){
        int L=tr[xv].l,R=tr[xv].r,mid=(L+R)/2;
        if(L==l&&R==r){
            tr[xv].sum+=z*(R-L+1);
            tr[xv].lz+=z;
            return;
        }
        pushdown(xv);
        if(r<=mid) modify(xv*2,l,r,z);
        else if(l>mid) modify(xv*2+1,l,r,z);
        else modify(xv*2,l,mid,z),modify(xv*2+1,mid+1,r,z);
        pushup(xv);
    }
    
    ll query(int xv,int l,int r){
        int L=tr[xv].l,R=tr[xv].r,mid=(L+R)/2;
        if(L==l&&R==r) return tr[xv].sum;
        pushdown(xv);
        if(r<=mid) return query(xv*2,l,r);
        else if(l>mid) return query(xv*2+1,l,r);
        else return query(xv*2,l,mid)+query(xv*2+1,mid+1,r);
    }
    
    void add(int x,int y,int z){
        int topx=tp[x],topy=tp[y];
        while(topx!=topy){
            if(dep[topx]<dep[topy]) swap(x,y),swap(topx,topy);
            modify(1,dfn[topx],dfn[x],z);
            x=fa[topx];topx=tp[x];
        }
        if(dep[x]<dep[y]) swap(x,y);
        modify(1,dfn[y],dfn[x],z);
    }
    
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<n;i++){
            int x,y;scanf("%d%d",&x,&y);
            x++,y++;
            addedge(x,y),addedge(y,x);
        }
        dfs1(1,0);num=0;
        dfs2(1,1);fa[1]=1;
        build(1,1,n);
        int q;cin>>q;
        while(q--){
            char id;cin>>id;
            if(id=='A'){
                int x,y,z;scanf("%d%d%d",&x,&y,&z);x++,y++;
                add(x,y,z);
            }
            else{
                int x;scanf("%d",&x);x++;
                printf("%lld
    ",query(1,dfn[x],las[x]));
            }
        }
        return 0;
    }
  • 相关阅读:
    C语言:计算并输出S=1+(1+2^0.5)+(1+2^0.5+3^0.5)...+(1+2^0.5+3^0.5+...+n^0.5)
    C语言:计算输出给定数组中每相邻两个元素的平均值的平方根之和。
    C语言:把分数最低的学生数据放入数组b所指的数组中,-从键盘输入若干字符串,写入文件myfile4中,用-1作字符输入结束的标志,
    C语言:根据形参c中指定的英文字母,按顺序打印出若干后继相邻字母,-主函数中放入一个带头节点的链表结构中,h指向链表的头节点。fun函数找出学生的最高分-使用插入排序法对字符串中的字符进行升序排序。-从文件中找到指定学号的学生数据,读入次学生数据,
    C语言:将形参s所指字符串中所有ASCII码值小于97的字符存入形参t所指字符数组中,
    负载测试、压力测试和性能测试的区别
    一个有广告的纸杯子的测试用例设计(黑盒测试用例设计)
    java中Comparator的用法
    java 判断字符串中 大小写字母 数字和其他字符个数方法
    java Socket和ServerSocket多线程编程
  • 原文地址:https://www.cnblogs.com/renjianshige/p/9507654.html
Copyright © 2020-2023  润新知