fzu 2277 Change (dfs序+线段树)

版权声明:希望能在自己成长的道路上帮到更多的人,欢迎各位评论交流 https://blog.csdn.net/yiqzq/article/details/81880599

原题地址:http://acm.fzu.edu.cn/problem.php?pid=2277

题意:给定一棵根为1, n个结点的树. 有q个操作,有两种不同的操作
( 1 ) 1 , v , k , x : a [ v ] + = x , a [ v ] + = x k ( v v ) , a [ v ] + = x 2 k ( v v ) . . . ;
( 2 ) 2 , v : a [ v ]

思路: 先 d f s 遍历, 得到这棵树的 d f s 序列, 并且记录每个结点的子孙(包括自己)的起始和结束位置, 以及每个结点的深度. 则对于1操作: v 的每个子孙结点的变化情况为 a [ i ] + = x ( d e e p [ i ] d e e p [ v ] ) k ; 其中 x + k d e e p [ v ] 对所有结点贡献相同,而 d e e p [ i ] k对每个结点的贡献度取决于结点i的深度. 所以可以用线段树, 对于每次操作一,所有v的子孙结点都加上 4 x + k d e e p [ v ] , 然后对于 d e e p [ i ] k 每次记录 k , 到最后更新的时候再乘以结点的深度即可.

#include <cmath>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <map>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 3e5 + 5;
const int mod = 1e9 + 7;
int n;
struct node {
    int v, nxt;
} e[maxn];
int tot, head[maxn];
int st[maxn], en[maxn], cnt, dep[maxn];
inline int read() {//读入挂
    int ret = 0, c, f = 1;
    for (c = getchar(); !(isdigit(c) || c == '-'); c = getchar());
    if (c == '-') f = -1, c = getchar();
    for (; isdigit(c); c = getchar()) ret = ret * 10 + c - '0';
    if (f < 0) ret = -ret;
    return ret;
}


void init_head() {
    tot = 0;
    cnt = 0;
    for (int i = 0; i <= n; i++) head[i] = -1;
}
inline void add_edge(int u, int v) {
    e[tot].v = v;
    e[tot].nxt = head[u];
    head[u] = tot++;
}

void dfs(int u, int d) {
    dep[cnt] = d;
    st[u] = cnt++;
    for (int i = head[u]; ~i; i = e[i].nxt) {
        int v = e[i].v;
        dfs(v, d + 1);
    }
    en[u] = cnt;
}
ll xx[maxn << 2], kk[maxn << 2];
void push_down(int rt) {
    xx[rt << 1] += xx[rt];
    xx[rt << 1 | 1] += xx[rt];
    kk[rt << 1] += kk[rt];
    kk[rt << 1 | 1] += kk[rt];
//     这边的取模去掉几乎快1倍的速度
//    xx[rt << 1] %= mod;
//    xx[rt << 1 | 1] %= mod;
//    kk[rt << 1] %= mod;
//    kk[rt << 1 | 1] %= mod;
    xx[rt] = 0;
    kk[rt] = 0;
}
void build(int l, int r, int rt) {
    xx[rt] = kk[rt] = 0;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(lson);
    build(rson);
}
void updata(int L, int R, ll x, ll k, int l, int r, int rt) {
    if (L <= l && R >= r) {
//        xx[rt] = (xx[rt] + x + mod) % mod;
        xx[rt] = xx[rt] + x ;
//        kk[rt] = (kk[rt] + k + mod) % mod;
        kk[rt] = kk[rt] + k;
        return;
    }
    push_down(rt);
    int mid = (l + r) >> 1;
    if (mid >= L) updata(L, R, x, k, lson);
    if (mid < R) updata(L, R, x, k, rson);
}

ll query(int p, int l, int r, int rt) {
    if (l == r) {
        return   xx[rt] + dep[l] * kk[rt];
//        return ans % mod;
    }
    push_down(rt);
    int mid = (l + r) >> 1;
    if (mid >= p) return query(p, lson);
    else return query(p, rson);
}

int main() {
    int t, q;
    t = read();
    while (t--) {
        n = read();
        init_head();
        for (int i = 2; i <= n; i++) {
            int x;
            x = read();
            add_edge(x, i);
        }
        dfs(1, 1);
        build(0, cnt - 1, 1);
        q = read();
        while (q--) {
            int op, x, v, k;
            op = read();
            if (op == 2) {
                x = read();
                ll ans = query(st[x], 0, cnt - 1, 1);
                ans = (ans % mod + mod) % mod;
                printf("%I64d\n", ans);
            } else {
                v = read();
                x = read();
                k = read();
                updata(st[v], en[v] - 1, x + 1LL * dep[st[v]]*k, -k, 0, cnt - 1, 1);
            }
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81880599