CF396C On Changing Tree

Solution

每个子树都对应DFS序上的一段区间。
发现所有操作要么只针对子树,要么只针对单个节点,因此我们可以利用DFS序将树上的操作转化为区间上的操作。
当我们更新节点 \(u\) 时,对于他的子节点 \(i\),它的变化值为\(x-(dep[i]-dep[u])*k=x+dep[u]*k-dep[i]*k\),我们只用记录\(x+dep[u]*k\)\(k\),最后就能算出答案。
用树状数组优化一下就过了。
因为树状数组或线段树的特性,想要利用它们优化区间更新,就需要找到该区间内每个元素相同的变化量。

Code:

#include <bits/stdc++.h>

using namespace std;

const int MAXN = 3e5 + 10;
const int MOD = 1e9 + 7;

vector<int> e[MAXN];
long long c1[MAXN],c2[MAXN],n,q,siz[MAXN],dep[MAXN],num[MAXN],cnt;

inline int lowbit(int x) {
    return (x & -x);
}

void update(long long x,long long val,long long k) {
    for (int i = x; i <= n; i += lowbit(i)) {
        c1[i] = (c1[i] + val) % MOD;c2[i] = (c2[i] + k) % MOD;
    }
}

long long query(int x,int u) {
    int sum1 = 0,sum2 = 0;
    for (int i = x; i > 0; i -= lowbit(i)) {
        sum1 = (sum1 + c1[i]) % MOD;sum2 = (sum2 + c2[i]) % MOD;
    }
    return ((sum1 - dep[u] * sum2) % MOD + MOD) % MOD;
}

void DFS(int u,int fa) {
    num[u] = ++cnt;
    int len = e[u].size();dep[u] = dep[fa] + 1;siz[u] = 1;
    for (int i = 0; i < len; i++) {
        DFS(e[u][i],u);
        siz[u] += siz[e[u][i]];
    }
    return;
}

int main() {
    scanf("%d",&n);
    for (int i = 2; i <= n; i++) {
        int u;
        scanf("%d",&u);
        e[u].push_back(i);
    }
    DFS(1,0);
    scanf("%d",&q);
    for (int i = 1; i <= q; i++) {
        int type;scanf("%d",&type);
        if (type == 1) {
            long long u,x,k;
            scanf("%lld%lld%lld",&u,&x,&k);
            update(num[u],(x + dep[u] * k) % MOD,k);
            update(num[u] + siz[u],-(x + dep[u] * k) % MOD,-k);
        }
        if (type == 2) {
            int u;
            scanf("%d",&u);
            printf("%lld\n",query(num[u],u));
        }
    }
    return 0;
}
posted @ 2021-08-02 23:33  kjd123456  阅读(57)  评论(0编辑  收藏  举报