zoukankan      html  css  js  c++  java
  • P3833 [SHOI2012]魔法树(树链剖分)

    题目背景

    SHOI2012 D2T3

    题目描述

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

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

    不幸的是,Harry 的法术学得不到位,只能对树上一段路径的节点上的果子个数统一增加一定的数量。也就是说,Harry 的魔法可以这样描述:A u v d 。表示将点 uu 和 vv 之间的路径上的所有节点的果子个数都加上 dd。

    接下来,为了方便检验 Harry 的魔法是否成功,你需要告诉他在释放魔法的过程中的一些有关果树的信息:Q u。表示当前果树中,以点 uu 为根的子树中,总共有多少个果子?

    输入格式

    第一行一个正整数 N (1 leq N leq 100000)N(1N100000),表示果

    树的节点总数,节点以 0,1,dots,N - 10,1,,N1 标号,00 一定代表根节点。

    接下来 N - 1N1 行,每行两个整数 a,b (0 leq a < b < N)a,b(0a<b<N),表示 aa 是 bb 的父亲。

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

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

    1. A u v d,表示将 uu 到 vv 的路径上的所有节点的果子数加上 dd。保证 0 leq u,v < N,0 < d < 1000000u,v<N,0<d<100000

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

    输出格式

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

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=1e6+100;
    int n,m;
    vector<int> g[maxn];
    int son[maxn];
    int id[maxn];
    int fa[maxn];
    int cnt;
    int dep[maxn];
    int size[maxn];
    int top[maxn];
    int w[maxn];
    int wt[maxn];
    
    struct node {
        int l,r;
        ll sum;
        ll lazy;
    }segTree[maxn*4];
    void build (int i,int l,int r) {
        segTree[i].l=l;
        segTree[i].r=r;
        if (l==r) {
            segTree[i].sum=wt[l];
            return;
        }
        int mid=(l+r)>>1;
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
        segTree[i].sum=segTree[i<<1].sum+segTree[i<<1|1].sum;
    } 
    void spread (int i) {
        if (segTree[i].lazy) {
            segTree[i<<1].sum+=segTree[i].lazy*(segTree[i<<1].r-segTree[i<<1].l+1);
            segTree[i<<1|1].sum+=segTree[i].lazy*(segTree[i<<1|1].r-segTree[i<<1|1].l+1);
            segTree[i<<1].lazy+=segTree[i].lazy;
            segTree[i<<1|1].lazy+=segTree[i].lazy;
            segTree[i].lazy=0;
        }
    }
    void update (int i,int l,int r,int val) {
        if (l<=segTree[i].l&&segTree[i].r<=r) {
            segTree[i].sum+=val*(segTree[i].r-segTree[i].l+1);
            segTree[i].lazy+=val;
            return;
        }
        spread(i);
        int mid=(segTree[i].l+segTree[i].r)>>1;
        if (l<=mid)
            update(i<<1,l,r,val);
        if (r>mid)
            update(i<<1|1,l,r,val);
        segTree[i].sum=segTree[i<<1].sum+segTree[i<<1|1].sum;
    }
    ll query (int i,int l,int r) {
        if (l<=segTree[i].l&&r>=segTree[i].r) 
            return segTree[i].sum;
        spread(i);
        int mid=(segTree[i].l+segTree[i].r)>>1;
        ll ans=0;
        if (l<=mid)
            ans+=query(i<<1,l,r);
        if (r>mid)
            ans+=query(i<<1|1,l,r);
        return ans;
    }
    
    ll qRange (int x,int y) {
        ll ans=0;
        while (top[x]!=top[y]) {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            ans+=query(1,id[top[x]],id[x]);
            x=fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        ans+=query(1,id[x],id[y]);
        return ans;
    }
    void upRange (int x,int y,int k) {
        while (top[x]!=top[y]) {
            if (dep[top[x]]<dep[top[y]]) swap(x,y);
            update(1,id[top[x]],id[x],k);
            x=fa[top[x]];
        }
        if (dep[x]>dep[y]) swap(x,y);
        update(1,id[x],id[y],k);
    }
    ll qSon (int x) {
        return query(1,id[x],id[x]+size[x]-1);
    }
    void dfs1 (int x,int f,int deep) {
        dep[x]=deep;
        fa[x]=f;
        size[x]=1;
        int maxson=-1;
        for (int y:g[x]) {
            if (y==f) continue;
            dfs1(y,x,deep+1);
            size[x]+=size[y];
            if (size[y]>maxson) son[x]=y,maxson=size[y];
        }
    }
    void dfs2 (int x,int topf) {
        id[x]=++cnt;
        wt[cnt]=w[x];
        top[x]=topf;
        if (!son[x]) return;
        dfs2(son[x],topf);
        for (int y:g[x]) {
            if (y==fa[x]||y==son[x]) continue;
            dfs2(y,y);
        }
    }
    int main () {
        scanf("%d",&n);
        for (int i=1;i<n;i++) {
            int u,v;
            scanf("%d%d",&u,&v);
            u++,v++;
            g[u].push_back(v);
            g[v].push_back(u);
        }
        dfs1(1,0,1);
        dfs2(1,1);
        build(1,1,n);
        scanf("%d",&m);
        while (m--) {
            string s;
            cin>>s;
            if (s=="A") {
                int u,v,d;
                scanf("%d%d%d",&u,&v,&d);
                u++;
                v++;
                upRange(u,v,d);
            }
            else {
                int u;
                scanf("%d",&u);
                u++;
                printf("%lld
    ",qSon(u));
            }
        }
    }
  • 相关阅读:
    Linux-OpenSUSE折腾-1(Qt安装,Chrome安装)
    Qt HUD(平显)演示程序绿色版
    你所不知道的按位运算
    Linux-Shell脚本编程-学习-8-函数
    Linux-Shell脚本编程-学习-7-总结前面开启后面的学习
    Linux-Shell脚本编程-学习-6-Shell编程-使用结构化命令-文件比较-case编程
    Linux-Shell脚本编程-学习-5-Shell编程-使用结构化命令-if-then-else-elif
    Linux-Shell脚本编程-学习-4-Shell编程-操作数字-加减乘除计算
    Linux-Shell脚本编程-学习-3-Shell编程-shell脚本基本格式
    selenium 总结篇,常见方法和页面元素的操作
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13466127.html
Copyright © 2011-2022 走看看