dfs序及相关例题

news2025/1/16 8:10:14

常用的三种dfs序

  • 欧拉序

每经过一次该点记录一次的序列。

  • dfs序

记录入栈和出栈的序列。

  • dfn序

只记录入栈的序列。

dfs序

DFS 序列是指 DFS 调用过程中访问的节点编号的序列。

在这里插入图片描述

如何求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);

一道简单的dfs序的问题。

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

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

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

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

在这里插入图片描述

观察上图:

  • 以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 序列中的连续一段(一段区间)。

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

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

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

AC代码:

#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
}

还有一个好题是这几天cfdiv2的F,这个F是牛客上的一个原题。

牛客:华华和月月种树 (nowcoder.com)

cf:Problem - F - Codeforces

个人题解链接:离线处理 + dfs序 + 区间修改 + 单点查询-CSDN博客

dfs序(基础讲解)-CSDN博客

[树 DFS序 详解完全版]_千杯湖底沙.的博客-CSDN博客

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1154460.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android开发,车载通讯应用——binder通讯原理解析

Binder简单理解 简单来说&#xff0c;Binder 就是用来Client 端和 Server 端通信的。并且 Client 端和 Server 端 可以在一个进程也可以不在同一个进程&#xff0c;Client 可以向 Server 端发起远程调用&#xff0c;也可以向Server传输数据&#xff08;当作函数参数来传&#…

JavaSE 优先级队列(堆)

目录 1 二叉树的顺序存储1.1 存储方式1.2 下标关系 2 堆(heap)2.1 概念2.2 操作-向下调整2.3 操作-建堆 3 堆的应用-优先级队列3.1 概念3.2 内部原理3.3 操作-入队列(向上调整)3.4 操作-出队列(优先级最高&#xff09;3.5 返回队首元素(优先级最高)3.6 java 中的优先级队列3.7 …

你工作中最推荐的 C/C++ 程序库有哪些,为什么?

你工作中最推荐的 C/C 程序库有哪些&#xff0c;为什么&#xff1f; 我主要做计算力学&#xff0c;说说平时用的一些c库1、前处理划网格用netgen&#xff0c;非结构网格功能强大&#xff0c;有可执行的软件和供调用的库&#xff0c;使用方便。 最近很多小伙伴找我&#xff0c;…

Trino 源码剖析

Functions function 反射和注册 io.trino.operator.scalar.annotations.ScalarFromAnnotationsParser 这里是提取注解元素的方法 String baseName scalarFunction.value().isEmpty() ? camelToSnake(annotatedName(annotated)) : scalarFunction.value(); 这里如果 scala…

早安心语微语早读,保持一颗平常心,坐看云起落花开谢得之淡然

1、保持一颗平常心&#xff0c;坐看云起落花开谢得之淡然&#xff0c;失之坦然&#xff0c;让生命中每一天都充满着阳光和希望&#xff01; 2、每个人都一样&#xff0c;都有一段独行的日子&#xff0c;或长或短&#xff0c;这都是无可回避的。不必总觉得生命空空荡荡&#xf…

QML 创建 Web 混合应用

作者: 一去、二三里 个人微信号: iwaleon 微信公众号: 高效程序员 随着互联网的快速发展,Web 应用在各个领域中变得越来越流行。为了满足用户对多样化功能的需求,我们经常需要将 Web 技术和原生应用相结合,来创建混合应用程序。 混合应用程序:是一种应用程序开发方法,它…

三款20万级B+级轿跑实力大PK,谁才是最优选?

近几年的车市,新能源汽车销量可谓节节升高,其中,可油可电、没有续航焦虑还能享受电动车行驾驶质感的混动车型,越来越被用户认可。在当前市场上的混动车型中,2024款哪吒S、比亚迪汉DM-i,一直都是大热选手,近期上市的零跑C01也欲成“追赶”之势。那么,这三款车中究竟谁能真正符合…

u盘直接拔出文件丢失怎么找回?u盘文件恢复办法分享!

u盘作为一种便捷的数据存储设备&#xff0c;被广泛地使用。通过u盘&#xff0c;我们可以在不同设备之间轻松传输文件&#xff0c;然而有时候&#xff0c;我们可能因为匆忙或疏忽并未安全弹出u盘&#xff0c;而是直接将u盘拔出&#xff0c;进而导致重要文件丢失&#xff0c;u盘直…

第20期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练 Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大型语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以…

10本值得阅读的量化交易书籍

什么是量化交易&#xff1f; 量化交易是利用数学模型或算法来创建交易策略并进行交易。量化交易通常由大型机构交易员或对冲基金雇用&#xff0c;他们雇用大量的博士和工程师团队。从历史上看&#xff0c;量化交易领域一直非常隐秘&#xff0c;有效的想法往往受到公司的严密保…

极智AI | 从大模型角度看苹果M3系列芯片

欢迎关注我的公众号 [极智视界],获取我的更多经验分享 大家好,我是极智视界,本文来介绍一下 从大模型角度看苹果M3系列芯片。 邀您加入我的知识星球「极智视界」,星球内有超多好玩的项目实战源码下载,链接:https://t.zsxq.com/0aiNxERDq 北京时间今天早上,Apple 发布了…

软文推广:让你的产品在市场中脱颖而出的法宝

软文推广为什么能成为企业宣传的常用手段&#xff0c;软文推广究竟能为企业带来什么&#xff1f;今天媒介盒子就来和大家分享&#xff0c;软文推广的五大效果。 一、 提升品牌曝光 软文发布能将带有品牌信息的软文发布到各类用户活跃度高、流量好的媒体&#xff0c;如果文案质…

链动2+1模式:白酒产品的营销新策略

链动21模式是一种创新的营销模式&#xff0c;结合白酒产品更能发挥其优势。该模式通过独特的身份晋升和奖励机制&#xff0c;快速建立销售渠道&#xff0c;提高用户粘性。 一、核心机制 身份晋升机制&#xff1a;用户购买指定499白酒产品后成为代理&#xff0c;再邀请两位用户…

linux 报错

输入 pip install -U openmim报错 有可能是服务器在其他国家&#xff0c;需要手动设置 把这三行复制到~/.bashrc里 export http_proxyhttp://127.0.0.1:3128 export https_proxy${http_proxy} export ftp_proxy${http_proxy}source ~/.bashrc

ATECLOUD如何进行电源模块各项性能指标的测试?

ATECLOUD平台进行电源模块各项性能指标的测试是通过以下步骤实现的&#xff1a; 连接测试设备&#xff1a;将测试设备与云计算服务器连接&#xff0c;实现数据采集和远程控制。测试设备包括示波器、电子负载、电源、万用表等&#xff0c;这些设备通过纳米BOX连接到云测试平台上…

Microsoft365个人版与家庭版有哪些功能区别?

Microsoft 365个人版与家庭版均能享受完整的Microsoft 365功能与权益&#xff0c;稍有不同的是&#xff0c;Microsoft 365家庭版可供6人使用&#xff0c;而个人版是仅供一人使用。 个人版可以同时登入5台设备&#xff0c;家庭版每人也可以登入5台设备&#xff0c;每个人都可以享…

扫描二维码填写信息怎么做?二维码生成表单的方法

当参加活动时&#xff0c;现在经常会发现申请活动都会通过扫码的方式来登记个人信息&#xff0c;那么对于这种登记类型的二维码是如何制作呢&#xff1f;想要通过扫码来登记信息&#xff0c;那么一般比较简单的方法就是在浏览器上利用二维码生成器来制作&#xff0c;这种方式的…

uni-app中使用手机号一键登录的详细图文教程

1、首先需要在dcloud开发者控制台开通一键登录 https://dev.dcloud.net.cn/uniLogin 开通一键登录服务, 获取关键最关键的两个参数ApiKey和ApiSecret 真机调试无需添加应用&#xff0c;如需打包使用请添加。一键登录应用ID为离线打包时配置的appid 2、登录云服务空间&#xff0…

智能井盖监测仪器的效果有哪些? 近些

年井盖事故频繁出现&#xff0c;尤其是在各个城市之中&#xff0c;由于井盖分布密集杂乱&#xff0c;并不能实行统一化管理&#xff0c;需要依靠传统人工巡查检修的方式&#xff0c;这就会带来更多的安全隐患。城市管理部门在对井盖进行监测只能依靠人工&#xff0c;监管不及时…

10-10 分层模式

Dao模式 程序员写的是业务(因为其逻辑性不太强) 软件设计原则:开闭原则&#xff0c;对新增加的进行开放&#xff0c;对修改关闭 实际开发中, web项目, 程序员编写业务代码 把所有的代码都写在业务方法中: 接收前端请求,获取请求参数… 编写业务代码处理请求 调用jdbc代码操…