洛谷P8972 『GROI-R1』 一切都已过去(树上前缀和+运算符重载)

『GROI-R1』 一切都已过去

题目背景

悦关上窗,拉上帘布。

果然还是想不起来啊。

隐约记得曾和什么人一起做过这样的事。

仰面躺下,手执一只木笺。

「究竟如何,才能拥有“过去”啊……」

她闭上双眼。

「6 岁前的记忆……究竟如何才能寻回?」

题目描述

悦正在寻找她的记忆。忽然,她来到了有 n n n 个节点的一棵树上。树上每一条边都有各自边权,每一个点都有各自的点权。

「把经历都聚拢起来,能完整地复原吗……」

悦从树上的一个点,慢慢地走到了另一个点,可是她什么也没找到。但是,她不知道,玘一直在远处望着她走过的道路。

玘发现,悦全程没有走回头路。他想把悦走过的每一条边的边权乘起来,可惜他发现他遇到了一个这一生未曾见到过的数字。

「为什么会这样呢?」

玘想到悦是突然出现在树上的,最初的点一定有蹊跷!他把最初那个点的点权乘上……

突然,一束彼岸花的红光亮起!世界重新安静了下来。

悦看到了玘留下的字样,可惜她不能从中看出任何过去的记忆。现在,你要帮她判断:把经历都聚拢起来,能完整地复原过去吗?我们称悦的一条路径能“复原过去”,当且仅当玘留下的乘积是一个整数

形式化题面

给定一棵 n n n 个节点的树和 q q q 次询问。每次询问给出两个整数 x , y x,y x,y,表示询问树上以 x x x y y y 为端点的简单路径上边权乘积与点 x x x 的点权相乘是否为整数。

输入格式

第一行两个正整数 n n n q q q,表示树上有 n n n 个节点编号为 1 ∼ n 1\sim n 1n,悦在树上走了 q q q 条路径。

接下来一行 n n n 个非负整数表示每个点的点权 a i a_i ai

接下来 n − 1 n-1 n1 行每行两个正整数 u , v u,v u,v 和一个非负实数 w w w 表示 u , v u,v u,v 间有一条边权为 w w w 的边。

接下来 q q q 行,每行两个正整数 x , y x,y x,y,表示悦从点 x x x 开始走到了点 y y y

输出格式

对于悦的每一次询问,你需要输出一行一个字符串。如果悦能够成功复原她的过去,请输出 Yes,否则请输出 No

样例 #1

样例输入 #1

5 3
1 2 3 4 5
1 2 0.1
2 3 0.20
3 4 0.5
2 5 0.99
1 5
1 4
4 3

样例输出 #1

No
No
Yes

提示

样例解释

根据输入可以得到下图:

对于第一个询问 ( 1 , 5 ) (1,5) (1,5) 可以发现悦经过的边的边权分别是 0.1 0.1 0.1 0.99 0.99 0.99,她出发的 1 1 1 号点的点权为 1 1 1 1 × 0.1 × 0.99 = 0.099 1\times0.1\times0.99=0.099 1×0.1×0.99=0.099 不是整数。所以输出 No

对于后面两次询问同理。

数据范围

本题采用捆绑测试。

子任务编号数据范围特殊性质分值
Subtask1 \text{Subtask1} Subtask1 n , q ≤ 3 × 1 0 3 n,q\le3\times 10^3 n,q3×103 15 15 15
Subtask2 \text{Subtask2} Subtask2 n ≤ 500 n\le500 n500 q ≤ 1 0 5 q\le10^5 q105 10 10 10
Subtask3 \text{Subtask3} Subtask3 n , q ≤ 1 0 5 n,q\le10^5 n,q105 BE \text{BE} BE 10 10 10
Subtask4 \text{Subtask4} Subtask4 n , q ≤ 1 0 5 n,q\le10^5 n,q105 A \text{A} A 5 5 5
Subtask5 \text{Subtask5} Subtask5 n , q ≤ 1 0 5 n,q\le10^5 n,q105 B \text{B} B 10 10 10
Subtask6 \text{Subtask6} Subtask6 n , q ≤ 1 0 5 n,q\le10^5 n,q105 C \text{C} C 5 5 5
Subtask7 \text{Subtask7} Subtask7 n , q ≤ 1 0 5 n,q\le10^5 n,q105 D \text{D} D 10 10 10
Subtask8 \text{Subtask8} Subtask8 n , q ≤ 2 × 1 0 5 n,q\le2×10^5 n,q2×105 35 35 35

特殊性质 A \text{A} A:保证树退化成一条链。

特殊性质 B \text{B} B:保证树随机生成(即对于每一个节点随机选择它的父亲节点)。

特殊性质 C \text{C} C:保证 w ∈ { 0.1 , 0.3 , 0.5 , 0.7 , 0.9 } w\in\{0.1,0.3,0.5,0.7,0.9\} w{0.1,0.3,0.5,0.7,0.9}

特殊性质 D \text{D} D:保证 w ∈ { 0.1 , 0.2 , 0.3 , 0.4 , 0.6 , 0.7 , 0.8 , 0.9 } w\in\{0.1,0.2,0.3,0.4,0.6,0.7,0.8,0.9\} w{0.1,0.2,0.3,0.4,0.6,0.7,0.8,0.9}

特殊性质 E \text{E} E:保证 w ≤ 2 w\le2 w2 w w w 小数位数不超过 1 1 1 位。

对于 100 % 100\% 100% 的数据满足 1 ≤ n , q ≤ 2 × 1 0 5 1\le n,q\le2\times10^5 1n,q2×105 0 ≤ a i ≤ 1 0 9 0\le a_i\le10^9 0ai109 0 ≤ w ≤ 1 0 4 0\le w\le10^4 0w104 1 ≤ u , v , x , y ≤ n 1\le u,v,x,y\le n 1u,v,x,yn x ≠ y x\ne y x=y w w w 小数位数不超过 4 4 4 位。

涉及知识:树上前缀和(LCA),运算符重载。

思路:对于树上两节点间距离或者权值和之类的问题很容易想到树上前缀和的思路,但是按照表面意思进行前缀和之间的乘法的话精度完全不够所以需要转换一下思维,为了让一个小数转换成整数,我们可以枚举一下看看。
得到的可以完成整数转换的其实只有一类:

//0.5*2 -> 0.1 * 5 * 2  --
//0.2*5	-> 0.1 * 5 * 2  ---> 0.1 * 10
//0.4*2.5 -> 0.01 * 5^2 * 2^2  ---> 0.01 * 10^2

因此,只需要统计一下2和5的次幂数以及所有小数点后位数之和,那么2和5组成的是的次幂数即 n u m 10 = m i n ( n u m 2 , n u m 5 ) num_{10} = min(num_2,num_5) num10=min(num2,num5) 。并比较其与小数点后位数之和的大小即得答案。
其中有两个坑点:
如果你的代码TLE了,可能是因为你没有考虑点权为0的情况。
如果你的代码WA了,可能是以为你没有考虑边权出现0的情况。
因此我们只需要特判一下以上两种情况就差不多解决这个问题了。

#include <bits/stdc++.h>
using namespace std;

#define all(x) x.begin(), x.end()
#define bit1(x) __builtin_popcount(x)
#define Pqueue priority_queue
#define lc p << 1
#define rc p << 1 | 1
#define IOS ios::sync_with_stdio(false), cin.tie(0);
#define fi first
#define se second

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<ll, ll> PII;

const ll mod = 1000000007;
const ll N = 1e6 + 10;
const ld eps = 1e-9;
const ll inf = 1e18;
const ll P = 131;
const ll dir[8][2] = {1, 0, 0, 1, -1, 0, 0, -1, 1, 1, 1, -1, -1, 1, -1, -1};

struct node
{
    int a, b, c;
} g[N];//定义一个结构体a,b,c依次对应小数点后位数、2的次幂数、5的次幂数
//即由1到第i个节点的树上前缀和
node operator*(node a, int b)
{
    return node({a.a * b, a.b * b, a.c * b});
}//重载运算符 *
node operator+(node a, node b)
{
    return node({a.a + b.a, a.b + b.b, a.c + b.c});
}//重载运算符 +
node operator-(node a, node b)
{
    return node({a.a - b.a, a.b - b.b, a.c - b.c});
}//重载运算符 -
ostream &operator<<(ostream &out, node a)
{
    out << a.a << " " << a.b << " " << a.c << "\n";
    return out;
}//重载运算符 << (用于Debug)
node check(double x)
{
    node tmp({0, 0, 0});
    if (x == 0)
        return tmp;
    while (x != (ll)x)
    {
        x *= 10;
        tmp.a++;
    }//取小数点后位数
    ll t = x;
    while (t % 2 == 0)
    {
        t /= 2;
        tmp.b++;
    }//取2的次幂数
    while (t % 5 == 0)
    {
        t /= 5;
        tmp.c++;
    }//取5的次幂数
    return tmp;
}//返回一个实数x包含的node信息

int fa[N][21];//父节点数组i的第2^j位父亲
int dep[N];	//深度数组
int Log2[N + 10];//预处理Log2数组
int zero[N];	//0的树上前缀和数组,由1到第i个节点路径上0的个数
int n, m, u, v;
double w;
vector<pair<int, double>> G[N];	//邻接表存图

void Dfs(int u, int f)		//DFS求LCA并构建树上前缀和
{
    dep[u] = dep[f] + 1;	//求深度
    fa[u][0] = f;			//u的第一个父亲是f
    for (int i = 1; i <= Log2[dep[u]]; i++)
        fa[u][i] = fa[fa[u][i - 1]][i - 1];	
        //u的第2^i个父亲是 (u的第2^{i-1}个父亲) 的第 2^{i-1} 个父亲
    for (auto [v, w] : G[u])	//遍历子节点
    {
        if (v == f)
            continue;
        zero[v] = zero[u] + (w==0);	//统计0的个数
        g[v] = g[u] + check(w);		//统计其他树上前缀和
        Dfs(v, u);
    }
}
int Lca(int a, int b)				//倍增法求LCA
{
    if (dep[a] > dep[b])
        swap(a, b);
    while (dep[a] != dep[b])
        b = fa[b][Log2[dep[b] - dep[a]]];
    if (a == b)
        return a;
    for (int i = Log2[dep[a]]; i >= 0; i--)
        if (fa[a][i] != fa[b][i])
            a = fa[a][i], b = fa[b][i];
    return fa[a][0];
}

void solve()
{
    // node a({1, 2, 3}), b({3, 2, 1});
    // cout << a * 2;
    // cout << a + b;
    // cout << a - b;
    cin >> n >> m;
    vector<int> val(n + 10);
    for (int i = 1; i <= n; i++)
        cin >> val[i];
    for (int i = 1; i < n; i++)
    {
        cin >> u >> v >> w;
        G[u].push_back({v, w});
        G[v].push_back({u, w});
    }
    Dfs(1, 0);
    // for (int i = 1; i <= n; i++)
    //     cout << g[i];
    for (int i = 1; i <= m; i++)
    {
        cin >> u >> v;
        node tmp = g[u] + g[v] - g[Lca(u, v)] * 2 + check(val[u]);
        //由 u 到 v 路径上的树上前缀和 + 点权中的信息
        // cout << check(cal[u]) << tmp;
        int z = zero[u] + zero[v] - zero[Lca(u, v)] * 2;	
        //0的树上前缀和
        if (!val[u] || z > 0 || min(tmp.b, tmp.c) >= tmp.a)
        //特判两个坑点
            cout << "Yes\n";
        else
            cout << "No\n";
    }
}

int main()
{
    Log2[0] = -1;
    for (int i = 1; i <= N; i++)
        Log2[i] = Log2[i / 2] + 1;//预处理Log2数组
    IOS int T = 1;
    // cin>>T;
    while (T--)
        solve();
    return 0;
}

/*
oxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxox
x                                                                                      o
o       _/_/_/_/                                                              _/       x
x      _/                                                                              o
o     _/_/_/_/ _/  _/_/   _/_/   _/_/_/ _/_/   _/_/_/     _/_/    _/_/_/    _/ _/   _/ x
x    _/       _/_/     _/    _/ _/   _/   _/  _/    _/ _/    _/  _/    _/  _/   _/ _/  o
o   _/       _/       _/    _/ _/   _/   _/  _/    _/ _/    _/  _/    _/  _/    _/_/   x
x  _/       _/         _/_/   _/   _/   _/  _/_/_/     _/_/ _/ _/    _/  _/      _/    o
o                                          _/                           _/      _/     x
x                                         _/                        _/_/       _/      o
o                                                                                      x
xoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxoxo
*/

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python Flask框架 -- url

这里限定了int&#xff0c;所以只能输入数字 完整代码&#xff1a; # 从flask这个包中导入Flask类 from flask import Flask, request# 使用Flask类创建一个app对象 # __name__ 代表当前app.py这个模块 app Flask(__name__)app.route(/blog/path) def hello_world():return H…

ThingsBoard初始化数据库Postgres

视频教程&#xff1a; ThingsBoard初始化数据库postgres_哔哩哔哩_bilibilihingsBoard是一个基于Java的开源物联网平台&#xff0c;旨在实现物联网项目的快速开发、管理和扩展。本课程主要从0到1带你熟悉ThingsBoard&#xff0c;学习优秀的物联网变成思维与思想&#xff0c;主…

C++ 笛卡尔树

目录 一、性质二、构建笛卡尔树三、应用四、源码 一、性质 堆性质&#xff1a; 笛卡尔树是一种满足堆性质的树。每个节点包含两个值&#xff1a;键值&#xff08;key&#xff09;和优先级值&#xff08;priority&#xff09;。在笛卡尔树中&#xff0c;根节点的优先级值最大&am…

【图论】拓补排序 - 邻接表

文章目录 题目&#xff1a;310. 最小高度树题目描述代码与注释 题目&#xff1a;310. 最小高度树 题目描述 代码与注释 func findMinHeightTrees(n int, edges [][]int) (ans []int) {if n 1 {return []int{0}}g : make([][]int, n)degree : make([]int, n) // 记录每个节点…

粤嵌6818开发板触摸屏应用

一、触摸屏应用 1.触摸屏设备的名字 在Linux下&#xff0c;一切皆文件&#xff0c;触摸屏也是一个文件。 触摸屏设备的名字&#xff1a;/dev/input/event0 2.触摸屏的两个专业术语 事件 ->event0 当一些外接控制设备(鼠标、键盘&#xff0c;wifi&#xff0c;触摸屏&am…

【Linux】信号保存{sigset_t/sigpending/sigprocmask/bash脚本/代码演示}

文章目录 1.信号相关常见概念2.管理信号的数据结构3.初识sigset_t4.信号集操作函数4.1sigpending4.2sigprocmask4.2代码测试1.测试12.测试23.测试3 4.3bash 脚本文件 1.信号相关常见概念 信号相关动作&#xff1a;产生 发送 接收 阻塞 递达(处理) 实际执行信号的处理动作称为信…

Spring Boot中application配置文件的生效顺序

Spring Boot的一个重要特性就是它的自动配置&#xff0c;这一特性在很大程度上依赖于名称为application的配置文件。本文将详细介绍在Spring Boot中&#xff0c;这些配置文件的加载顺序以及每份文件的应用范围。 文章目录 配置文件的种类配置文件的加载顺序配置文件的环境切换 …

一起玩儿3D打印机——03 Marlin固件的获取和安装环境的配置

摘要&#xff1a;本文介绍Marlin固件的获取和安装环境的配置 Marlin是一款开源软件&#xff0c;其主页为&#xff1a;https://marlinfw.org/&#xff0c;首页正中就是下载连接&#xff0c;如下图所示&#xff1a; 单击下面的“Download Marlin 2.1.2.2”按钮就会进入下载页面&a…

图形设计软件 CorelDRAW Graphics Suite 2024 v25.0.0.230 中文破解版

CorelDRAW Graphics Suite (简称CDR) 是加拿大Corel公司开发的一款功能强大的专业平面设计软件、矢量设计软件、矢量绘图软件。软件广泛应用于商标设计、标志制作、封面设计、CIS设计、产品包装造型设计、模型绘制、插图描画、时装/服饰设计、印刷制版、排版及分色输出等诸多领…

linux查看top与修改root密码

top perf top -g -p 进程名 使用top命令&#xff0c;同时输入大写的P&#xff0c;会按照cpu使用率从大到小排列 linux修改用户登录密码 输入Ctrlx进入下面的界面 分别输入mount -o remount, rw / 注意rw后面又两个空格 输入passwd root 修改root密码 输入新密码2次 ex…

三、传输层拥塞控制、差错控制

3.1 概述和传输层服务 传输服务和协议&#xff1a; 为运行在不同主机上的应用进程提供逻辑通信&#xff1b; 传输协议运行在端系统-发送方:将应用层的报文分成报文段&#xff0c;然后传递给网络层&#xff1b;接收方&#xff1a;将报文段重组成报文&#xff0c;然后传递给应用…

解决分布式事务,Seata真香!

年IT寒冬&#xff0c;大厂都裁员或者准备裁员&#xff0c;作为开猿节流主要目标之一&#xff0c;我们更应该时刻保持竞争力。为了抱团取暖&#xff0c;林老师开通了《知识星球》&#xff0c;并邀请我阿里、快手、腾讯等的朋友加入&#xff0c;分享八股文、项目经验、管理经验等…

Anaconda安装proplot库

看了一下Anaconda中的环境&#xff0c;现在我有4个&#xff0c;其中gee是一个虚拟环境 因此一般在prompt中装库时要先进入其中一个虚拟环境 conda activate geepip install proplot --no-deps下完了之后&#xff0c;发现版本不对应 conda install matplotlib3.4.3

传输层 | UDP | TCP

目录 一、再谈端口号 (一) 端口号范围划分 (二) 认识知名端口号 (三) netstat (四) pidof 二、UDP协议 (一) UDP协议端格式 (二) UDP的特点 (三) 面向数据报 (四) UDP的缓冲区 (五) UDP使用注意事项 (六) 基于UDP的应用层协议 三、TCP协议 (一) TCP协议的段格式 …

数据结构——lesson8二叉树的实现

&#x1f49e;&#x1f49e; 前言 hello hello~ &#xff0c;这里是大耳朵土土垚~&#x1f496;&#x1f496; &#xff0c;欢迎大家点赞&#x1f973;&#x1f973;关注&#x1f4a5;&#x1f4a5;收藏&#x1f339;&#x1f339;&#x1f339; &#x1f4a5;个人主页&#x…

鸿蒙Harmony应用开发—ArkTS声明式开发(基础手势:Web)中篇

onBeforeUnload onBeforeUnload(callback: (event?: { url: string; message: string; result: JsResult }) > boolean) 刷新或关闭场景下&#xff0c;在即将离开当前页面时触发此回调。刷新或关闭当前页面应先通过点击等方式获取焦点&#xff0c;才会触发此回调。 参数…

Parade Series - Web Streamer Low Latency

Parade Series - FFMPEG (Stable X64) 延时测试秒表计时器 ini/config.ini [system] homeserver storestore\nvr.db versionV20240312001 verbosefalse [monitor] listrtsp00,rtsp01,rtsp02 timeout30000 [rtsp00] typelocal deviceSurface Camera Front schemartsp ip127…

uniapp,导航栏(切换项)有多项,溢出采取左滑右滑的形式展示

一、实现效果 当有多项的导航&#xff0c;或者说切换项&#xff0c;超出页面的宽度&#xff0c;我们采取可滑动的方式比较好一些&#xff01;并且在页面右边加个遮罩&#xff0c;模拟最右边有渐变效果&#xff01; 二、实现代码 html代码&#xff1a; <!-- 头部导航栏 --…

Linux:系统初始化,内核优化,性能优化(3)

优化系统的文件句柄数&#xff08;全局&#xff09; 也就是系统的最大文件数量 查看最大数量 cat /proc/sys/fs/file-max 当我们的服务器有非常大的一个数据并发的时候十几二十万的文件需要去配置&#xff0c;可能这个是远远不够的&#xff0c;我们就要去修改 vim /etc/sy…

【系统架构师】-第4章-信息安全技术

1、基础知识 五要素&#xff1a; (1)机密性&#xff1a;确保信息不暴露给未授权的实体或进程。 (2)完整性&#xff1a;只有得到允许的人才能修改数据&#xff0c;并且能够判别出数据是否已被篡改。 (3)可用性&#xff1a;得到授权的实体在需要时可访问数据&#xff0c;即攻击…