FZU 2277 (dfs序+线段树)

用dfs序可以维护出所有子节点
对于更新,我们将更新变为 deep[i]kdeep[j]k d e e p [ i ] k − d e e p [ j ] k deep[j]k d e e p [ j ] k 就是当前自己的深度,是可以直接计算的,那么对于 deep[i]k d e e p [ i ] k ,就是父亲节点的深度,另外别忘了还有 x x ,所以我们对于父亲节点的所有儿子首先更新x+deep[i]k lazy l a z y 标记下放 k k ,就能做到x+deep[i]kdeep[j]k


然后这题把 xvk x 、 v 、 k 改成全局变量才能过??这是什么问题


#include <iostream>
#include <algorithm>
#include <queue>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <set>
#include <cmath>
#include <map>
#include <sstream>
#define LL long long
#define INF 0x3f3f3f3f
#define mod 1000000007
#define eps 1e-8
const int maxn = 300000 + 5;
using namespace std;
vector<int> vec[maxn];
int idx;
int ver[maxn];
int L[maxn];
int R[maxn];
int n;
int deep[maxn];
LL lazy[maxn*4];
LL a[maxn*4];
int v;
LL x,k;
int op;
void dfs(int cur, int fa, int step){
    L[cur] = ++idx;
    ver[idx] = cur;
    deep[idx] = step;
    for(int i=0; i<vec[cur].size(); i++){
        int v = vec[cur][i];
        if(v != fa){
            dfs(v,cur,step+1);
        }
    }
    R[cur] = idx;
}
void pushdown(int o){
    if(lazy[o]){
        lazy[o*2] += lazy[o];
        lazy[o*2] %= mod;
        lazy[o*2+1] += lazy[o];
        lazy[o*2+1] %= mod;
        lazy[o] = 0;

    }
    if(a[o]){
        a[o*2] += a[o];
        a[o*2] %= mod;
        a[o*2+1] += a[o];
        a[o*2+1] %= mod;
        a[o] = 0;
    }
}
void build(int l, int r, int o) {
    if(l == r){
        a[o] = 0;
        return ;
    }
    int m = (l + r) / 2;
    build(l,m,o*2);
    build(m+1,r,o*2+1);
}
LL query(int l, int r, int o, int v){
    if(l == r){
        return(a[o] + deep[l]*lazy[o] % mod + mod) % mod;
    }
    pushdown(o);
    int m = (l + r) / 2;
    if(m >= v)
        return query(l,m,o*2,v);
    else
        return query(m+1,r,o*2+1,v);

}
void update(int l, int r, int o, int ql, int qr, LL c, LL k){
    if(ql <= l && qr >= r){
        lazy[o] = ((lazy[o] + k) % mod + mod) % mod;
        a[o] = ((a[o] + c) % mod + mod) % mod ;
        return ;
    }
    pushdown(o);
    int m = (l + r) / 2;
    if(m >= ql) update(l,m,o*2,ql,qr,c,k);
    if(m < qr) update(m+1,r,o*2+1,ql,qr,c,k);
}
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        idx = 0;
        for(int i=0; i<maxn; i++)
            vec[i].clear();
        memset(deep, 0, sizeof(deep));
        memset(lazy, 0, sizeof(lazy));
        memset(a, 0, sizeof(a));
        scanf("%d",&n);
        for(int i=2; i<=n; i++){
            int x;
            scanf("%d",&x);
            vec[x].push_back(i);
        }
        dfs(1,-1,1);
        build(1,n,1);
        int q;
        scanf("%d",&q);
        while(q--){
            scanf("%d",&op);
            if(op == 1){
                scanf("%d%lld%lld",&v,&x,&k);
                update(1, n, 1, L[v], R[v], deep[L[v]]*k + x, -k);
            }
            else{
                scanf("%d",&v);
                printf("%lld\n",(query(1,n,1,L[v]) % mod + mod) % mod);
            }
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值