题解 | #求和#

求和

https://ac.nowcoder.com/acm/problem/204871

一道简单的dfs序的问题。

题目链接:求和 (nowcoder.com)

问题描述:n个节点,n - 1条边,根节点为k。现在又m个操作。

  • 1 a x:将节点a的权值加上x
  • 2 a:求a节点的子树上所有节点的和(包括a节点本身)

思路,发现以a为根的子树权值和是一个非线性的,不能用树状数组或者线段树来做。但是dfs序却有一个天然的顺序可以来处理。 alt 如何求dfs序?可以用以下代码来找dfs序。

    vector<vector<int>> g(n+1);
    for(int i = 1; i < n; ++i) {
        // u,v 建图
        int u,v; u = fread(); v = fread();
        g[u].push_back(v);
        g[v].push_back(u);
    }
    // dfs序的左右端点
    // 表示以x为根的子树的左右端点位置
    vector<int> l(n + 1), r(n + 1);
    int cnt = 0;
    // 一个dfs找dfs序
    auto dfs = [&](auto &&self, int u, int fa) -> void {
        l[u] = ++cnt;
        for(auto y: g[u]) {
            if(y == fa) continue;
            self(self, y,u);
        }
        r[u] = cnt;
    };
    dfs(dfs, k,-1);

思路,发现以a为根的子树权值和是一个非线性的,不能用树状数组或者线段树来做。但是dfs序却有一个天然的顺序可以来处理。 alt

观察上图:

  • 以5为根的子树序列在dfs序中的排序是:1 2 3 4 5 6 7 8

  • 以8为根的子树序列在dfs序中的排序是:2 3

  • 以2为根的子树序列在dfs序中的排序是:3

  • 以1为根的子树序列在dfs序中的排序是:4 5 6 7 8

...

DFS(图论) - OI Wiki (oi-wiki.org)

因此本题思路就是:用dfs序将非序列顺序转线性序列。之后就是单点修改,区间查询,可以用树状数组或者线段树来进行求解。

本人是用线段树来进行处理的(线段树大法好

#include <iostream>
#include <vector>
#include <string>
#include <cstring>
#include <set>
#include <map>
#include <queue>
#include <ctime>
#include <random>
#include <sstream>
#include <numeric>
#include <stdio.h>
#include <functional>
#include <bitset>
#include <algorithm>
using namespace std;

// #define Multiple_groups_of_examples
#define int_to_long_long
#define IOS std::cout.tie(0);std::cin.tie(0)->sync_with_stdio(false); // 开IOS,需要保证只使用Cpp io流 *
#define dbgnb(a) std::cout << #a << " = " << a << '\n';
#define dbgtt cout<<" !!!test!!! "<<'\n';
#define rep(i,x,n) for(int i = x; i <= n; i++)

#define all(x) (x).begin(),(x).end()
#define pb push_back
#define vf first
#define vs second

typedef long long LL;
#ifdef int_to_long_long
#define int long long
#endif
typedef pair<int,int> PII;

const int INF = 0x3f3f3f3f;
const int N = 2e5 + 21;


struct SegTree {
    static const int N = 1e6 + 21;
    struct node {
        int l, r, mi;
        LL sum,add;
    }tr[N << 2];
    int w[N];
    // 左子树
    inline int ls(int p) {return p<<1; }
    // 右子树
    inline int rs(int p) {return p<<1|1; }
    // 向上更新
    void pushup(int u) {
        tr[u].sum = tr[ls(u)].sum + tr[rs(u)].sum;
        tr[u].mi = min(tr[ls(u)].mi, tr[rs(u)].mi);
    }
    // 向下回溯时,先进行更新
    void pushdown(int u) { // 懒标记,该节点曾经被修改,但其子节点尚未被更新。
        auto &root = tr[u], &right = tr[rs(u)], &left = tr[ls(u)];
        if(root.add) {
            right.add += root.add; right.sum += (LL)(right.r - right.l + 1)*root.add; right.mi -= root.add;
            left.add += root.add; left.sum += (LL)(left.r - left.l + 1)*root.add; left.mi -= root.add;
            root.add = 0;
        }

    }
    // 建树
    void build(int u, int l, int r) {
        if(l == r) tr[u] = {l, r, w[r], w[r], 0};
        else {
            tr[u] = {l,r}; // 容易忘
            int mid = l + r >> 1;
            build(ls(u), l, mid), build(rs(u), mid + 1, r);
            pushup(u);
        }
    }
    // 修改
    void modify(int u, int l, int r, int d) {
        if(tr[u].l >= l && tr[u].r <= r) {
            tr[u].sum += (LL)(tr[u].r - tr[u].l + 1)*d;
            tr[u].add += d;
        }
        else {
            pushdown(u);
            int mid = tr[u].l + tr[u].r >> 1;
            if(l <= mid) modify(ls(u), l ,r, d);
            if(r > mid) modify(rs(u), l, r, d);
            pushup(u);
        }
    }
    // 查询
    LL query(int u, int l, int r) {
        if(tr[u].l >= l && tr[u].r <= r) {
            return tr[u].sum;
        }
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        LL sum = 0;
        if(l <= mid) sum = query(ls(u), l, r);
        if(r > mid ) sum += query(rs(u), l, r);
        return sum;
    }
}tree;
// 当输入数据大于 1e6 时用快读
inline int fread() // 快读
{
    int x = 0, f = 1; char ch = getchar();
    while(ch < '0' || ch > '9') {if (ch == '-') f = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') {
        x = x * 10 + (ch - '0');
        ch = getchar();
    }
    return x * f;
}
void inpfile();
void solve() {
    // int n,m,k; cin>>n>>m>>k;
    int n = fread(), m = fread(), k = fread();
    vector<int> a(n + 1);
    for(int i = 1; i <= n; ++i) a[i] = fread();
    vector<vector<int>> g(n+1);
    for(int i = 1; i < n; ++i) {
        int u,v; u = fread(); v = fread();
        g[u].push_back(v);
        g[v].push_back(u);
    }
    vector<int> l(n + 1), r(n + 1);
    int cnt = 0;
    auto dfs = [&](auto &&self, int u, int fa) -> void {
        l[u] = ++cnt;
        for(auto y: g[u]) {
            if(y == fa) continue;
            self(self, y,u);
        }
        r[u] = cnt;
    };
    dfs(dfs, k,-1);
    for(int i = 1; i <= n; ++i) tree.w[l[i]] = a[i];
    tree.build(1,1,n);
    while(m--) {
        int opt,x,y; opt = fread();
        if(opt == 2) {
            // cin>>x>>y;
            x = fread();
            cout<<tree.query(1, l[x], r[x])<<'\n';
        } else {
            x = fread(), y = fread();
            tree.modify(1,l[x],l[x],y);
        }
    }
}
#ifdef int_to_long_long
signed main()
#else
int main()
#endif

{
    #ifdef Multiple_groups_of_examples
    int T; cin>>T;
    while(T--)
    #endif
    solve();
    return 0;
}
void inpfile() {
    #define mytest
    #ifdef mytest
    freopen("ANSWER.txt", "w",stdout);
    #endif
}
全部评论

相关推荐

不愿透露姓名的神秘牛友
2024-12-30 18:02
程序员牛肉:1.可以标记一下自己的学校是985,有一些hr可能没想到你这个院校是985的。 2.简历所呈现出来的能力还是有点差的,苍穹外卖+黑马点评。这在java技术域里面也就是刚学三四个月的样子,大厂现在招人少,小厂又更加希望你能直接过来干活。就你简历上呈现出来的能力,确实是有点难找,肉眼可见的不懂技术。 第一个项目中:简单的使用redis也算是亮点嘛?使用jwt,threadlocal也算是亮点?你不就是调了几个包嘛?Nginx作为服务器也能写出来,这不是前端的活嘛? 第二个项目中:分布式锁+mq消息队列+Lua队列。真没啥好问的。属于面试官看一眼就阳痿的简历,没有任何想提问的欲望。 我给你建议是好好的挖一挖这个项目吧,其实苍穹外卖和黑马点评这两个项目很不错了,只不过是太烂大街了导致面试官没啥问的兴趣,所以不太推荐写简历上。
点赞 评论 收藏
分享
01-23 14:54
同济大学 Java
热爱敲代码的程序媛:给你提几点【专业技能】这个模块里面可优化的地方:1.【具备JVM调优经验】可以去b站上搜一下JVM调优的视频,估计一两个小时凭你的学习能力就能掌握JVM调优的实践方面的技能。2.【MySql优化】MySql这一栏,你去b站或者找个博客看看MySql优化,学一下,如果你本身比较熟悉MySql语句的话,那基本半天时间凭你的学习能力MySql语句优化方面的技能你也能掌握个差不多。以上1,2两点主要是因为我看你专业技能大部分都说的是偏理论,没有写应用。再就是最后,你结合你的项目,想一想你的项目中哪些sql语句是可以用MySql优化的,到时候你面试的时候也好结合着说一下。
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客企业服务