• 1076E/Educational Codeforces Round 54-E. Vasya and a Tree<<dfs序 树状数组


    题意

    给定一棵树,初始每个节点权值为零,q次更改,每次修改将以v为顶点的深度为d的子树全部加上x,最后输出所有节点的权重。

    思路

    题目只要求每个点最后的值,那么经过观察,发现一个点最后的权值大小只与他的父节点的更新有关,那么我们就只需要考虑他的父节点到他这条链上的情况,把这条链拿出来成为线段,然后维护后缀和就能得到此点上的权值。每个节点的贡献为给$[h,h+d]$增加$x$,所以维护时,只要在$h+d$点上加上$x$即可。

    但是问题考察的是一棵树,我们就需要动态来完成这条链,我们采用dfs序去扫描这棵树,当一个节点进入时,把他的贡献算上,退出时减去他的贡献,这样就能保证他不会影响别的链。

    代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 typedef pair<int,int> PII;
     4 const int maxn=3e5+7;
     5 vector<PII> query[maxn];
     6 vector<int> G[maxn];
     7 long long tree[maxn];
     8 long long ans[maxn];
     9 int depth[maxn],reflect[maxn];
    10 int st[maxn],ed[maxn];
    11 void dfs(int now,int far)
    12 {
    13     static int tot=0;
    14     st[now]=++tot;
    15     reflect[tot]=now;
    16     if(far==-1)
    17     {
    18         depth[now]=1;
    19     }
    20     for(int i=0;i<G[now].size();i++)
    21     {
    22         int v=G[now][i];
    23         if(v==far) continue;
    24         depth[v]=depth[now]+1;
    25         dfs(v,now);
    26     }
    27     ed[now]=tot;
    28 }
    29 void add(int x,int v)
    30 {
    31     while(x<maxn)
    32     {
    33         tree[x]+=v;
    34         x+=x&-x;
    35     }
    36 }
    37 long long sum(int x)
    38 {
    39     long long ret=0;
    40     while(x>0)
    41     {
    42         ret+=tree[x];
    43         x-=x&-x;
    44     }
    45     return ret;
    46 }
    47 int main()
    48 {
    49     int n;
    50     memset(tree,0,sizeof(tree));
    51     scanf("%d",&n);
    52     for(int i=1,u,v;i<=n-1;i++)
    53     {
    54         scanf("%d%d",&u,&v);
    55         G[u].push_back(v);
    56         G[v].push_back(u);
    57     }
    58     dfs(1,-1);//跑出dfs序
    59     int q;
    60     scanf("%d",&q);
    61     while(q--)//存储所有询问,将他们按节点分开转换为dfs序的树上顺序
    62     {
    63         int v,d,x;
    64         scanf("%d%d%d",&v,&d,&x);
    65         d+=depth[v];
    66         d=min(d,n);
    67         query[st[v]].push_back(make_pair(d,x));
    68         query[ed[v]+1].push_back(make_pair(d,-x));//在退出时清除贡献
    69     }
    70     for(int i=1;i<=n;i++)
    71     {
    72         for(int j=0;j<query[i].size();j++)//把这个节点上更新的都更新了
    73         {
    74             PII temp=query[i][j];
    75             add(temp.first,temp.second);
    76         }
    77         ans[reflect[i]]=sum(n)-sum(depth[reflect[i]]-1);//映射返回得到答案
    78     }
    79     for(int i=1;i<=n;i++)
    80     {
    81         printf("%lld ",ans[i]);
    82     }
    83 }
  • 相关阅读:
    Java中的并发库学习总结
    Android源码的git下载地址
    Android下载Android源码
    工具类 验证手机邮箱
    hibernate缓存说明
    Hibernate之N+1问题
    常用正则
    Java Base64加密、解密原理Java代码
    Base64加密解密原理以及代码实现(VC++)
    情书经典语录
  • 原文地址:https://www.cnblogs.com/computer-luo/p/9970985.html
Copyright © 2020-2023  润新知