Educational Codeforces Round 54 E. Vasya and a Tree 树上前缀和或树状数组

Educational Codeforces Round 54 E. Vasya and a Tree

树上前缀和


#include <bits/stdc++.h>
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define Pb push_back
#define FI first
#define SE second
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<<endl<<"DEBUG"<<endl; 
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
LL qpow(LL a,LL b){LL s=1;while(b>0){if(b&1)s=s*a%mod;a=a*a%mod;b>>=1;}return s;}
LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
int dr[2][4] = {1,-1,0,0,0,0,-1,1};
typedef pair<LL,LL> P;
const int maxn = 3e5+100;
LL add[maxn];
LL res[maxn];
vector<LL> G[maxn];
vector<P> command[maxn];
int n,m;
void dfs(int node,int h,int fa,LL sum){
    for(auto c: command[node])
    {
        int l = h,r = l + c.first;
        add[l] += c.second;
        if(r+1 <= n)
            add[r+1] -= c.second;
    }
    sum += add[h];
    res[node] = sum;
    for(auto c: G[node]){
        if(c == fa) continue;
        dfs(c,h+1,node,sum);
    }
    sum -= add[h];
    for(auto c: command[node])
    {
        int l = h,r = l + c.first;
        add[l] -= c.second;
        if(r+1 <= n)
            add[r+1] += c.second;
    }
}
int main(void)
{  
    cin>>n;
    for(int i = 0,v,u;i < n-1; ++i){
        scanf("%d%d",&v,&u);
        G[v].Pb(u);
        G[u].Pb(v);
    }
    cin>>m;
    for(int i = 0,v,h,x;i < m; ++i){
        scanf("%d%d%d",&v,&h,&x);
        command[v].Pb(P(h,x));
    }
    dfs(1,0,-1,0);

    for(int i = 1;i <= n; ++i)
        printf("%lld%c",res[i]," \n"[i==n]);
        

    return 0;
}

树状数组

分析

// 假设我们通过dfs序进入u节点,我们把它对于子节点的贡献都加上,相当于区间修改,树状数组的节点是深度
// 出去这个节点的时候把u把u节点的影响减去,因为u节点对于其它的没有贡献
// 树状数组是前缀和,所以我们区间修改的时候 修改的是一段区间,[l,l+h],我们其实可以当成是修改[1,l+h];,这样也不会对[l+h+1,n] 的有影响
// 所以可以把深度都取反


#include <bits/stdc++.h>
#define mem(ar,num) memset(ar,num,sizeof(ar))
#define me(ar) memset(ar,0,sizeof(ar))
#define lowbit(x) (x&(-x))
#define Pb push_back
#define FI first
#define SE second
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define IOS ios::sync_with_stdio(false)
#define DEBUG cout<<endl<<"DEBUG"<<endl; 
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int    prime = 999983;
const int    INF = 0x7FFFFFFF;
const LL     INFF =0x7FFFFFFFFFFFFFFF;
const double pi = acos(-1.0);
const double inf = 1e18;
const double eps = 1e-6;
const LL     mod = 1e9 + 7;
LL qpow(LL a,LL b){LL s=1;while(b>0){if(b&1)s=s*a%mod;a=a*a%mod;b>>=1;}return s;}
LL gcd(LL a,LL b) {return b?gcd(b,a%b):a;}
int dr[2][4] = {1,-1,0,0,0,0,-1,1};
typedef pair<int,int> Pii;
typedef pair<LL,LL> PLL;
const int maxn = 3e5+100;
LL tree[maxn];// 线段树

void Add(int x,int p){
    x++;
    while(x < maxn){
        tree[x] += p;
        x += lowbit(x);
    }
}
LL Sum(int x){
    LL ans = 0;
    x++;
    while(x > 0){
        ans += tree[x];
        x -= lowbit(x);
    }
    return ans;
}
LL depth[maxn];
int id[maxn];// id[i] 代表节点i的dfs序
int vs[maxn];// vs[i] 代表dfs序为i的节点编号
int ed[maxn];// 打表子树中最大的dfs序

LL ans[maxn];
std::vector<int> G[maxn];
std::vector<PLL> Q[maxn];
int k = 0;
void dfs(int node,int fa){
    id[node] = ++k;
    vs[k] = node;
    // depth[node] = d;/
    for(auto c: G[node]){
        if(c == fa) continue;
        depth[c] = depth[node]+1;
        dfs(c,node);
    }
    ed[node] = k;
}
int main(void)
{
    int n;
    cin>>n;
    for(int i = 2;i <= n; ++i){
        int u,v;
        scanf("%d%d",&u,&v);
        G[u].Pb(v);
        G[v].Pb(u);
    }
    depth[1] = 1;
    dfs(1,-1);
    int m;
    cin>>m;
    for(int i = 1;i <= m; ++i){
        LL u,d,v;
        scanf("%lld%lld%lld",&u,&d,&v);
        Q[id[u]].Pb(PLL(min(depth[u]+d,(LL)n),v));
        Q[ed[u]+1].Pb(PLL(min(depth[u]+d,(LL)n),-v));
    }
    for(int i= 1;i <= n; ++i){
        for(auto c: Q[i]){
            Add(n-c.first,c.second);
        }
        ans[vs[i]] = Sum(n-depth[vs[i]]);
    }
    for(int i = 1;i <= n; ++i)
        cout<<ans[i]<<" ";
    

   return 0;
}


全部评论

相关推荐

昨天 10:10
已编辑
门头沟学院 人工智能
写这篇之前我犹豫了挺久。一方面是怕被人骂,&quot;又一个收割焦虑的转行帖&quot;;另一方面是看了太多用&nbsp;GPT&nbsp;套娃出来的「学习路线」文章,AI&nbsp;味重得让人没法读完。所以这篇全是亲身踩过的坑,时间线、用过的项目、当时的心路全都尽量原样写出来。如果你是大学生在迷茫要不要转&nbsp;AI,或者已经在转的路上,希望能给点参考。&nbsp;一个反共识的开场:你以为进&nbsp;OpenAI&nbsp;的人都是博士?&nbsp;先讲个故事,跟我没关系,但跟所有想转&nbsp;AI&nbsp;的人都有关系。&nbsp;OpenAI&nbsp;的&nbsp;Sora&nbsp;团队(就是搞文生视频那个)一共&nbsp;13&nbsp;个人。这里面有两个人特别有意思:&nbsp;Will&nbsp;DePue,密歇根大学计算机系,直接辍学了。17...
_hengheng:我也本,也算是做ai相关,我最开始感觉做ai工程师有多么多么困难,后来发现懂了原理后整体训练完全可以看成一个流程化的内容,开源方案太多了,大多基本都是按着模子在自家业务上做各种操作,就算是大厂的小部门也没那么多资源去训基模,反而更多的是像怎么把技术往业务方向靠近了,不过当前时代如果本科学历没那么好加上自己执行力不是特别强还真不建议走ai工程师这条路,可以试试其他ai的偏业务方向,不然校招不太好杀出来
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务