• 19.10.01 acm E:Lowest Common Ancestor


    题目描述

    一棵有根树,对于每个点 $i$ ,求 $sum_{j=1}^{i-1}w_{lca(i,j)}$

    数据范围

    $n le 2 imes 10^5,1 le w_i le 10^4$

    题解

    我们可以考虑枚举 $lca$ 去更新答案

    对于每个点 $x$ ,如果它成为两个点的 $lca$ ,那这两个点肯定来自不同的子树

    那我们可以建立一个线段树表示这个区间的答案总和(?),然后进行线段树合并即可

    具体地话就是考虑合并到 $x,y$ 两个节点上,那 $x$ 的左儿子会对 $y$ 的右儿子造成贡献,同理 $y$ 的左儿子会对 $x$ 的右儿子造成贡献,所以我们再多维护一个区间有多少个数出现即可

    代码

    #include <bits/stdc++.h>
    using namespace std;
    const int N=2e5+5,M=N*50;
    int a[N],TT,n,T[N],t,nx[N],hd[N],V[N];
    int s[M],f[M],ls[M],rs[M],tg[M];
    void add(int u,int v){
        nx[++t]=hd[u];V[hd[u]=t]=v;
    }
    #define mid ((l+r)>>1)
    void insert(int &x,int l,int r,int v){
        s[x=++t]++;
        if (l==r) return;
        if (mid>=v) insert(ls[x],l,mid,v);
        else insert(rs[x],mid+1,r,v);
    }
    void down(int x){
        if (ls[x]) f[ls[x]]+=tg[x],tg[ls[x]]+=tg[x];
        if (rs[x]) f[rs[x]]+=tg[x],tg[rs[x]]+=tg[x];
        tg[x]=0;
    }
    int merge(int x,int y,int c,int d,int v){
        if (!x && !y) return 0;
        if (!x){f[y]+=d*v;tg[y]+=d*v;return y;}
        if (!y){f[x]+=c*v;tg[x]+=c*v;return x;}
        down(x);down(y);int z=++t;
        ls[z]=merge(ls[x],ls[y],c,d,v);
        rs[z]=merge(rs[x],rs[y],c+s[ls[y]],d+s[ls[x]],v);
        f[z]=f[ls[z]]+f[rs[z]];
        s[z]=s[ls[z]]+s[rs[z]];
        return z;
    }
    void dfs(int x,int fr){
        insert(T[x],1,n,x);
        for (int i=hd[x];i;i=nx[i])
            if (V[i]!=fr){
                dfs(V[i],x),
                T[x]=merge(T[x],T[V[i]],0,0,a[x]);
            }
    }
    void put(int x,int l,int r){
        if (l==r){
            if (l>1) printf("%d
    ",f[x]);return;
        }
        down(x);put(ls[x],l,mid);put(rs[x],mid+1,r);
    }
    void work(){
        t=0;
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]),hd[i]=0;
        for (int i=2,x;i<=n;i++)
            scanf("%d",&x),add(x,i);t=0;
        dfs(1,0);put(T[1],1,n);
        for (int i=1;i<=t;i++)
            ls[i]=rs[i]=tg[i]=f[i]=s[i]=0;
    }
    int main(){
        while(~scanf("%d",&n)) work();
        return 0;
    }
  • 相关阅读:
    小学二年级四则运算软件需求规格说明书
    周活动总结
    构建之法阅读笔记01
    学习进度条01
    四则运算
    软件工程概论
    课后作业1
    继承与多态-课后作业
    python文件处理-将图像根据坐标画矩形标记
    python文件处理-将图像根据坐标切割成若干小图
  • 原文地址:https://www.cnblogs.com/xjqxjq/p/11623667.html
Copyright © 2020-2023  润新知