Codeforces 396C On Changing Tree(树状数组)

来源:互联网 发布:第十三届复杂网络大会 编辑:程序博客网 时间:2024/05/16 13:40

题目链接:Codeforces 396C On Changing Tree


题目大意:给出一棵以1为根的树,形式是从节点2开始给出每个节点的父亲节点;然后是m次操作,操作分为两种,1 v, x, k,表示在以v为根的字数上添加,添加的法则是看这个节点与v节点的距离为i的话,加上x-i*k;2 v查询节点v的值。


解题思路:一开始以为很难,但是突然想到可以先加上在减去就豁然开朗了。首先dfs一遍树,将树映射成树状数组上的位置l[u] ~r[u]表示以u为根的树的范围。然后开两个数组,ad记录添加值,su记录需要减掉得值。关键是在添加的时,添加在ad数组中x+k*d[u],添加在su数组中k。然后在计算最后答案的时候Sum(ad) - d[u]*Sum(su) (即在最后一步在一起减掉,然后ad数组中每次k*d[u]就保证了不会多减,d为节点的层数)注意最后答案要mod1e9+7,而且注意负数的情况,有时负的很大的话,加一个mod是不够的,可以先取模后再加。


#include <stdio.h>#include <string.h>#include <vector>#include <iostream>using namespace std;typedef long long ll;const int N = 3*1e5+10;const ll mod = 1e9+7;int n, k, l[N], r[N], d[N];ll ad[N], su[N];vector<int> g[N];void dfs(int u, int deep) {k++;l[u] = k;d[u] = deep;for (int i = 0; i < g[u].size(); i++)dfs(g[u][i], deep+1);r[u] = k;}void init () {memset(ad, 0, sizeof(ad));memset(su, 0, sizeof(su));int a;scanf("%d", &n);for (int i = 2; i <= n; i++) {scanf("%d", &a);g[a].push_back(i);}k = 0;dfs(1, 0);}void add(int x, ll val, ll* bit) {while (x <= k) {bit[x] = (bit[x] + val) % mod;x += (x&(-x));}}ll query(int u) {int x = l[u];ll a = 0, b = 0;while (x) {a += ad[x];b += su[x];x -= (x&(-x));}return ((a - b*d[u])%mod + mod) % mod;}int main () {init();int key, v;ll x, y;scanf("%d", &n);for (int i = 0; i < n; i++) {scanf("%d%d", &key, &v);if (key == 1) {cin >> x >> y;ll val = (x + d[v] * y) % mod;add(l[v], val, ad);add(r[v]+1, -val, ad);add(l[v], y, su);add(r[v]+1, -y, su);} else {cout << query(v) << endl;}}return 0;}


1 0
原创粉丝点击