家庭主妇问题

news2025/2/21 23:25:47

一 问题描述

X 村的人们住在美丽的小屋里。若两个小屋通过双向道路连接,则可以说这两个小屋直接相连。X 村非常特别,可以从任意小屋到达任意其他小屋,每两个小屋之间的路线都是唯一的。温迪的孩子喜欢去找其他孩子玩,然后打电话给温迪:“妈咪,带我回家!”。在不同的时间沿道路行走所需的时间可能不同。温迪想告诉她的孩子她将在路上花的确切时间。

二 输入和输出说明

1 输入

第 1 行包含 3 个整数 n 、q 、s,表示有 n 个小屋、q 个消息,温迪目前在 s 小屋里,n <100001,q <100001。以下 n -1 行各包含 3 个整数 a、b 和 w ,表示有一条连接小屋 a 和 b 的道路,所需的时间是 w (1≤w≤10000)。以下 q 行有两种消息类型:

① 消息 A,即 0 u ,孩子在小屋 u 中给温迪打电话,温迪应该从现在的位置去小屋 u ;

② 消息 B,即 1 i w ,将第 i 条道路所需的时间修改为 w 

注意:温迪在途中时,时间不会发生改变,时间在温迪停留在某个地方等待孩子时才会改变)。

2 输出

对每条消息 A,都输出一个整数,即找到孩子所需的时间。

三 输入和输出用例

1 输入样例

3 3 1

1 2 1

2 3 2

0 2

1 2 3

0 3

2 输出样例

1

3

四 分析

本问题中任意两个小屋都可以相互到达,且路径唯一,明显是树形结构。可以将边权看作点权,对一条边,让深度 dep 较大的点存储边权。对边 u 、v ,边权为 w ,若 dep[u ]>dep[v ],则视 u 的权值为 w 。本问题包括树上点更新、区间和查询。可以用树链剖分将树形结构线性化,然后用线段树进行点更新、区间和查询。

解决方案:树链剖分+线段树。

五 算法设计

1 第 1 次深度优先遍历求 dep、fa、size、son,第 2 次深度优先遍历求 top、id、rev。

2 创建线段树。

3 点更新,u 对应的下标 i =id[u],将其值更新为 val。

4 区间查询,求 u 、v 之间的和值。若 u 、v 不在同一条重链上,则一边查询,一边向同一条重链靠拢;若 u 、v 在同一条重链上,则根据节点的下标在线段树中进行区间查询。

注意:因为在本题中是将边权转变为点权,所以实际查询的区间应为 query(1, id[son[u]], id[v])。

六 代码

package com.platform.modules.alg.alglib.poj2763;

public class Poj2763 {
    private int maxn = 100010;
    int head[] = new int[maxn]; //头结点
    int cnt = 0;
    int total = 0;
    int fa[] = new int[maxn]; // 父亲
    int dep[] = new int[maxn]; // 深度
    int size[] = new int[maxn]; // 子树结点总数
    int son[] = new int[maxn]; // 重儿子
    int top[] = new int[maxn]; // 所在重链顶端结点
    int id[] = new int[maxn];
    int rev[] = new int[maxn]; // u 对应的 dfs 序下标,下标对于的 u
    int Sum;
    Edge1 a[] = new Edge1[maxn];

    edge e[] = new edge[maxn << 1];

    node tree[] = new node[maxn << 2];

    public Poj2763() {
        for (int i = 0; i < a.length; i++) {
            a[i] = new Edge1();
        }
        for (int i = 0; i < e.length; i++) {
            e[i] = new edge();
        }
        for (int i = 0; i < tree.length; i++) {
            tree[i] = new node();
        }
    }

    public String output = "";

    public String cal(String input) {
        int n, q, s;
        init();

        String[] line = input.split("\n");
        String[] words = line[0].split(" ");
        n = Integer.parseInt(words[0]);
        q = Integer.parseInt(words[1]);
        s = Integer.parseInt(words[2]);

        for (int i = 1; i < n; i++) {
            String[] info = line[i].split(" ");
            a[i].u = Integer.parseInt(info[0]);
            a[i].v = Integer.parseInt(info[1]);
            a[i].w = Integer.parseInt(info[2]);
            add(a[i].u, a[i].v);
            add(a[i].v, a[i].u);
        }
        dep[1] = 1;
        dfs1(1, 0);
        dfs2(1, 1);
        build(1, 1, total);//创建线段树
        for (int i = 1; i < n; i++) {
            if (dep[a[i].u] > dep[a[i].v]) {
                int temp = a[i].u;
                a[i].u = a[i].v;
                a[i].v = temp;
            }
            update(1, id[a[i].v], a[i].w);
        }
        int opt, i, val, x;
        while (q-- > 0) {
            String[] query = line[n++].split(" ");
            opt = Integer.parseInt(query[0]);

            if (opt == 1) {
                i = Integer.parseInt(query[1]);
                val = Integer.parseInt(query[2]);
                update(1, id[a[i].v], val); // 改变第 i 条边的值为 val
            } else {
                x = Integer.parseInt(query[1]);
                Sum = 0;
                ask(s, x);//查询s->x路径上边权的和值
                output += Sum + "\n";
                s = x;//更新温迪的位置
            }
        }
        return output;
    }

    void add(int u, int v) {
        e[++cnt].to = v;
        e[cnt].next = head[u];
        head[u] = cnt;
    }

    void init() {
        cnt = total = 0;
    }

    // 求dep,fa,size,son
    void dfs1(int u, int f) {
        size[u] = 1;
        for (int i = head[u]; i > 0; i = e[i].next) {
            int v = e[i].to;
            if (v == f)//父节点
                continue;
            dep[v] = dep[u] + 1;//深度
            fa[v] = u;
            dfs1(v, u);
            size[u] += size[v];
            if (size[v] > size[son[u]])
                son[u] = v;
        }
    }

    // 求 top,id,rev
    void dfs2(int u, int t) {
        top[u] = t;
        id[u] = ++total;//u对应的dfs序下标
        rev[total] = u;//dfs序下标对应的结点u
        if (son[u] == 0)
            return;
        dfs2(son[u], t);//沿着重儿子dfs
        for (int i = head[u]; i > 0; i = e[i].next) {
            int v = e[i].to;
            if (v != fa[u] && v != son[u])
                dfs2(v, v);
        }
    }

    // 点更新,线段树的第 k 个值为 val
    void update(int i, int k, int val) {
        if (tree[i].l == k && tree[i].r == k) {
            tree[i].sum = val;
            return;
        }
        int mid = (tree[i].l + tree[i].r) / 2;
        if (k <= mid) update(i << 1, k, val);
        else update((i << 1) | 1, k, val);
        tree[i].sum = tree[i << 1].sum + tree[(i << 1) | 1].sum;
    }

    // 初始化线段树,i 表示存储下标,区间[l,r]
    void build(int i, int l, int r) {
        tree[i].l = l;
        tree[i].r = r;
        tree[i].sum = 0;
        if (l == r) return;
        int mid = (l + r) / 2;//划分点
        build(i << 1, l, mid);
        build((i << 1) | 1, mid + 1, r);
    }

    // 查询线段树中 [l,r] 的和值
    void query(int i, int l, int r) {
        if (tree[i].l >= l && tree[i].r <= r) {//找到该区间
            Sum += tree[i].sum;
            return;
        }
        int mid = (tree[i].l + tree[i].r) / 2;
        if (l <= mid) query(i << 1, l, r);
        if (r > mid) query((i << 1) | 1, l, r);
    }

    void ask(int u, int v) {//求u,v之间的和值
        while (top[u] != top[v]) {//不在同一条重链上
            if (dep[top[u]] < dep[top[v]]) {
                int temp = u;
                u = v;
                v = temp;
            }

            query(1, id[top[u]], id[u]);//u顶端结点和u之间
            u = fa[top[u]];
        }
        if (u == v) return;
        if (dep[u] > dep[v]) {//在同一条重链上
            int temp = u; //深度小的结点为u
            u = v;
            v = temp;
        }
        query(1, id[son[u]], id[v]);//注意是son[u]
    }
}

class edge {
    int to, next;
}

// 结点
class node {
    int l, r, sum; // l,r区间左右端点,区间和值
}

class Edge1 {
    int u, v, w;
}

七 测试

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

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

相关文章

C++中TCP socket传输文件

在两个文件中都定义文件头和用到的宏&#xff1a; #define MAX_SIZE 10 #define ONE_PAGE 4096 struct FileHead {char str[260];int size; }; 在客户端发送接收阶段&#xff1a; //1.发送文件头char path[260] {0};cout<<"请输入文件路径"<<endl;cin…

数字图像处理MATLAB

数字图像处理MATLAB 基&#xff08;本&#xff09;操&#xff08;作&#xff09; 图片读取 Aimread(test.bmp); imshow(A);2. 图像写入 Aimread(test.bmp); imwrite(A,test-bak.bmp); Bimread(test-bak.bmp); imshow(B);3. 图像文件信息查询 infoimfinfo(test.bmp);4. 显示…

【创建型】生成器模式(Builder)

目录生成器模式(Builder)适用场景生成器模式实例代码&#xff08;Java&#xff09;生成器模式(Builder) 将一个复杂对象的构建与它的表示分离&#xff0c;使得同样的构建过程可以创建不同的表示。 适用场景 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方…

【SpringBoot笔记22】SpringBoot框架集成Redis数据库

这篇文章&#xff0c;主要介绍SpringBoot框架如何集成Redis数据库。 目录 一、SpringBoot集成Redis 1.1、引入依赖 1.2、配置redis连接信息 1.3、添加RedisTemplate配置类 1.4、编写测试类 1.5、运行测试 一、SpringBoot集成Redis Redis是一个非关系型数据库&#xff0c…

PCIe ECAM机制访问PCIE的配置空间

1.PCIe ECAM机制 PCI Express Enhanced Configuration Access Mechanism (ECAM)是访问PCIe配置空间的一种机制。是将PCIe的配置空间映射到MEM空间&#xff0c;使用MEM访问其配置空间的一种实现。可参考NCB-PCI_Express_Base_5.0r1.0-2019-05-22.pdf的第7.2.2小节。 其地址映射…

上海亚商投顾:沪指录得6连阳 两市成交再度破万亿

上海亚商投顾前言&#xff1a;无惧大盘大跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 市场情绪 三大指数今日横盘震荡&#xff0c;收盘集体小幅上扬&#xff0c;日K线均录得6连阳。虚拟现实概念股集体拉升&#…

【SA-Token】授权 鉴权中心微服务

授权 鉴权中心微服务 1 什么是JWT 1.2 JWT 的基本概念 1.3 JSON Web Token jwt 是一个开放标准 它定义了一种紧凑的、自包含的方式 用于作为JSON 对象在各方之间安全地传输信息 1.4.那些场景下可以考虑使用JWT &#xff1f; ​ 1.用户授权 信息交换 1.5 JWT的结构及其含义 …

镜频抑制滤波器对射频接收前端输出噪声的影响

射频接收前端包括LNA、Filter、Mixer等部件&#xff0c;从噪声因子级联的角度讲&#xff0c;希望接收链路第一级为高增益、低噪声系数放大器&#xff0c;以期望得到较低的系统噪声系数&#xff0c;提高接收灵敏度。除LNA外&#xff0c;接收链路还有一个关键的部件——镜频抑制滤…

精读大型网站架构:前端架构模块化的方法及困境,自研框架Trick

模块化的方法 网页和网页之间有很多相似或者相同的模块&#xff0c;模块化就是把这些模块抽离并独立管理。而模块化的方法&#xff0c;就是把模块的HTML、CSS和JavaScript文件独立出来&#xff0c;然后通过某种方法关联到使用这些模块的网页上。 在介绍模块化的具体方法之前&…

consul--基础--05--api

consul–基础–05–api 1、介绍 主要接口是RESTful HTTP API&#xff0c;该API可以用来增删查改nodes、services、checks、configguration。所有的endpoints主要分为以下类别 kv&#xff1a;Key/Value存储agent&#xff1a;Agent控制catalog&#xff1a;管理nodes和serviceshe…

数据结构-例题实训作业-二叉树相关

第1关:以先序的方式建立二叉树 任务描述 本关任务:以先序的方式建立二叉树并显示(顺时针90度后看) 相关知识 为了完成本关任务,你需要掌握: 1.二叉树的概念 2.二叉树的先序遍历方式 3.二叉树的遍历。 编程要求 在以下空白处补写代码,以先序方式完成二叉树的建立。 //…

计算机组成原理浮点数表示

浮点数表示 浮点数的表示分为阶码和尾数&#xff1b; 比如3.026*1011;阶码是11;尾数是3.026&#xff1b; 对于阶码&#xff1a; 阶符为正&#xff0c;小数点向后移n位&#xff08;n表示阶的大小&#xff09;; 阶符为负&#xff0c;小数点向前移n位&#xff08;n表示阶的大小&a…

基础IO(上)——Linux

文章目录1.储备知识2. 文件描述符2.1 c接口2.2 直接使用系统接口2.3 open函数返回值2.4 文件描述符fd2.5 周边文件3. 重定向3.1 输出重定向3.2 输出重定向3.3 追加重定向3.4 dup4. 如何理解一切皆文件&#xff1f;1.储备知识 对文件的操作范畴&#xff1a; 在系统角度理解文件 …

R语言生物群落数据统计分析

R 语言作的开源、自由、免费等特点使其广泛应用于生物群落数据统计分析。生物群落数据多样而复杂&#xff0c;涉及众多统计分析方法。本教学以生物群落数据分析中的最常用的统计方法回归和混合效应模型、多元统计分析技术及结构方程等数量分析方法为主线&#xff0c;通过多个来…

中医-通过舌象判断身体状况

本文分享通过舌象判断身体的整体状况&#xff08;中医角度&#xff09;&#xff0c;得出一个可供辨证的参考&#xff0c;并且可以根据舌象做出相关的饮食调整&#xff0c;本文主讲理论&#xff0c;相关舌象图片易引人不适&#xff0c;如需找相关图片&#xff0c;可根据本文中的…

【SpringBoot】一文了解SpringBoot配置高级

文章目录前言ConfigurationProperties使用场景小结宽松绑定/松散绑定&#x1f315;博客x主页&#xff1a;己不由心王道长&#x1f315;! &#x1f30e;文章说明&#xff1a;SpringBoot配置高级&#x1f30e; ✅系列专栏&#xff1a;SpringBoot &#x1f334;本篇内容&#xff1…

javaweb JavaScript快速入门 对象 BOM DOM 事件监听

JavaScript 引入方式 1.内部脚本&#xff1a;将 JS代码定义在HTML页面中 2.外部脚本&#xff1a;将 JS代码定义在外部 JS文件中&#xff0c;然后引入到 HTML页面中 JavaScript 基础语法 windows.alert可以省略windows var: 1.作用域为全局变量 2.变量可以重复定义 &#xf…

半桥LLC谐振变换器及同步整流MATLAB仿真(一)

在开关电源中&#xff0c;LLC谐振变换器是最常见的DC-DC变换器之一。 LLC谐振电路早在上世纪80年代就已经提出&#xff0c;到如今仍有广泛的应用&#xff0c;可见其优越性。其优点表现在&#xff1a; 1.LLC的开关器件能实现软开关&#xff0c;开关损耗小 2.效率高、功率密度大 …

[附源码]计算机毕业设计JAVA 宠物医院管理系统

[附源码]计算机毕业设计JAVA 宠物医院管理系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybati…

计算结构体大小(内存对齐原则)struct、union、class

这篇博客详细的介绍结构体的大小sizeof&#xff1a;union、struct、class。 一、不同数据类型所占的内存大小&#xff1a; 二、union联合体的结构体大小 1、关注点&#xff1a; &#xff08;1&#xff09;联合体的大小为所有成员变量中所占字节数最大的&#xff1b; &#xf…