Educational Codeforces Round 54 E - Vasya and a Tree 树上:离线+dfs+树状数组

题意:

给定一棵包含n个结点的树,开始每个结点权值为0,现在有q个操作,每个操作包含 v, d, x,表示第v号结点,以及再往下(对于树:他的孩子方向)遍历d层,访问到的结点权值都加上x;

输出所有结点的权值

思路:

一下想到的就是区间更新,单点查询,想写个树剖来着,感觉有点麻烦,然后就想到了树状数组很快的那个区间更新,前缀和当单点查询的操作,

然后再想想就想到了把所有操作离线出来,然后dfs遍历树的时候更新每个结点的操作,回溯的时候在更新回去,这样在更新到某个结点的时候,他的祖先结点的所有更新都全了;

复杂度O(n*log(maxn)+q)吧算是;

 

 

#include
using namespace std;
#define out fflush(stdout);
#define fast ios::sync_with_stdio(0),cin.tie(0);
#define FI first
#define SE second
typedef long long ll;
typedef pair P;
const int maxn = 3e5;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll mod = 998244353;

int n, m;
ll v, d, x;
vector vec[maxn+7];

ll c[maxn + 7];
void add(int id, ll x) {
    for(int i = id; i <= maxn; i += (i&-i)) {
        c[i] += x;
    }
}
ll sum(int id) {
    ll res = 0;
    for(int i = id; i > 0; i -= (i&-i)) {
        res += c[i];
    }
    return res;
}

vector

q[maxn+7]; ll ans[maxn+7]; void dfs(int id, int cnt, int f) { for(auto i : q[id]) { ll d = i.FI, x = i.SE; add(cnt, x); add(cnt+d+1, -x); } ans[id] = sum(cnt); for(auto i : vec[id]) { if(i == f) continue; dfs(i, cnt+1, id); } for(auto i : q[id]) { ll d = i.FI, x = i.SE; add(cnt, -x); add(cnt+d+1, x); } } int main() { scanf("%d", &n); int u, v; for(int i = 1; i < n; ++i) { scanf("%d%d", &u, &v); vec[u].push_back(v); vec[v].push_back(u); } scanf("%d", &m); for(int i = 1; i <= m; ++i) { scanf("%lld%lld%lld", &v, &d, &x); q[v].push_back(P(d,x)); } dfs(1, 1, -1); for(int i = 1; i <= n; ++i) { printf("%lld%c", ans[i], (i == n ? '\n' : ' ')); } return 0; }

 

你可能感兴趣的:(DFS,树状数组,codefoces)