一棵树初始只有一个结点1,根为1,有q(1e5)次操作:1、选择p结点,在p结点插入一个结点,编号为tot+1,2、选择p结点,使p的子树的所有结点权值都加上x。求q次操作后所有结点的权值(初始为0)

这篇文章描述了如何使用C++解决一个涉及区间更新和查询的问题,场景是在给定图中,对特定时间点生成的节点进行权值操作并计算最终影响。通过dfs遍历和低位运算优化查询效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
const int maxn = 1e6 + 5, inf = 1e9 + 5, maxm = 1e6 + 5, mod = 1e9 + 7;
int a[maxn], b[maxn], c[maxn];
int n, m;
map<int, int> mp;
// int suf[maxn], pre[maxn];
// bool vis[maxn];
int tot, q;
int tim[maxn];
vector<int> G[maxn];
struct Data{
    int tim, val;//时间,权值
};
vector<Data> dat[maxn];
int t[maxn];//t[i]表示在[i - lowbit(i) + 1, i]的时间段上生成的结点都(注意是都!)能加到的权值
int ans[maxn];

int lowbit(int x){
    return x & -x;
}
void insert(int x, int k){//在[1, x]时间段上的结点都加上k
    for(int i = x; i >= 1; i -= lowbit(i)){
        t[i] += k;
    }
}
int ask(int x){//询问在x时间生成的结点能加到的权值和
    int res = 0;
    for(int i = x; i <= q; i += lowbit(i)){
        res += t[i];
    }
    return res;
}
void dfs(int u){
    for(auto x : dat[u]){
        insert(x.tim, x.val);
    }
    ans[u] = ask(tim[u]);
    for(auto v : G[u]){
        dfs(v);
    }
    for(auto x : dat[u]){//回溯要减去该结点的影响
        insert(x.tim, -x.val);
    }
}
void solve()
{
    // cin >> n >> m;
    // for(int i = 1; i <= n; i++){
    //     cin >> a[i];
    // }
    // int q;
    cin >> q;
    for(int i = 1; i <= q; i++){
        G[i].clear();
        dat[i].clear();
        t[i] = 0;
    }
    tot = 1;
    tim[1] = 1;
    for(int i = 1; i <= q; i++){
        int op, p, x;
        cin >> op;
        if(op == 1){
            cin >> p;
            tot++;
            G[p].pb(tot);
            tim[tot] = i;
        }
        else{
            cin >> p >> x;
            dat[p].pb({i, x});
        }
    }
    dfs(1);
    for(int i = 1; i <= tot; i++){
        cout << ans[i] << " \n"[i == tot];
    }
}
signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    int T = 1;
    cin >> T;
    while (T--)
    {
        solve();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

__night_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值