1. 程式人生 > >Educational Codeforces Round 54 E. Vasya and a Tree 樹上字首和或樹狀陣列

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;
}