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

news2025/1/13 7:46:33

『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
*/

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

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

相关文章

ConsiStory:Training-Free的主体一致性生成

Overview 一、总览二、PPT详解 ConsiStory 一、总览 题目&#xff1a; Training-Free Consistent Text-to-Image Generation 机构&#xff1a;NVIDIA, Tel-Aviv University 论文&#xff1a;https://arxiv.org/pdf/2402.03286.pdf 代码&#xff1a;https://consistory-paper.g…

Python自动获取指定上市公司的所有财务数据(资产负债表,利润表,现金流量表)

案例背景 很多经管类同学找财务数据都很困难&#xff0c;去找一个个查找特定的公司&#xff0c;然后又要去同花顺或者东方财富网一年一年的去查看报表&#xff0c;一年一年的数据一个个填入...太慢了。 tushare能获取金融数据的接口&#xff0c;他有资产负债表&#xff0c;利…

idea warning:java源值已过时将在未来所有发行版中删除

在idea中运行maven项目 如果出现idea warning:java源值已过时将在未来所有发行版中删除&#xff0c;详见如下截图所示&#xff1a; 注意&#xff1a;jdk8 要解决这个警告需要设置3个地方 首先打开File->Project Structure中的Project&#xff0c;将SDK和language level都设…

Java学习笔记(15)

JDK7前时间相关类 Date时间类 Simpledateformat Format 格式化 Parse 解析 默认格式 指定格式 EE&#xff1a;表示周几 Parse&#xff1a;把字符串时间转成date对象 注意&#xff1a;创建对象的格式要和字符串的格式一样 Calendar日历类 不能创建对象 Getinstance 获取当…

Python笔记|字符串合并、切片、索引

一、合并 字符串可以用 合并&#xff08;粘到一起&#xff09;&#xff0c;也可以用 * 重复&#xff1a; >>> 3 * un ium unununium 相邻的两个或多个字符串字面值&#xff08;引号标注的字符&#xff09;会自动合并&#xff1a; >>> Py thon Python …

蓝桥杯每日一题 走迷宫bfs 超超详细解释!!!

昨天学习了bfs的基本概念&#xff0c;今天来做一道经典习题练练手吧&#xff01; bfs常用的两类题型 1.从A出发是否存在到达B的路径(dfs也可) 2.从A出发到B的最短路径&#xff08;数小:<20才能用dfs&#xff09; 遗留的那个问题的答案- 题目&#xff1a;走迷宫 答案&…

【Java刷题篇】串联所有单词的子串

这里写目录标题 &#x1f4c3;1.题目&#x1f4dc;2.分析题目&#x1f4dc;3.算法原理&#x1f9e0;4.思路叙述✍1.进窗口✍2.判断有效个数✍3.维护窗口✍4.出窗口 &#x1f4a5;5.完整代码 &#x1f4c3;1.题目 力扣链接: 串联所有单词的子串 &#x1f4dc;2.分析题目 阅…

力扣L14--- 415.字符串相加(JAVA版)-2024年3月17日

1.题目 2.知识点 注1&#xff1a;你可以使用Integer.parseInt()或Double.parseDouble()等方法将字符串转换为整数或浮点数。 public class Main {public static void main(String[] args) {String str "123";int num Integer.parseInt(str);System.out.println(…

如何在Mac中删除照片?这里有详细步骤

前言 本文介绍如何从Mac中删除照片,以释放硬盘空间或更好地组织文件和文件夹。 如何使用废纸篓删除Mac上的图片 在Mac上删除图片的最简单方法之一是使用废纸篓功能。学习只需几秒钟。下面是如何删除单个图片以及如何在Mac上删除多个图片,以及一些关键和有用的提示,以使该…

2023全球国际专利申请数量公布:华为遥遥领先三星、高通、苹果~

华为、三星和高通在2023年的国际专利申请数量上位居前三甲&#xff0c;其中来自中国的公司大幅度超越韩国和美国的高科技竞争对手。世界知识产权组织&#xff08;WIPO&#xff09;最新发布的数据显示&#xff0c;即使面临美国严厉制裁严重影响其在全球市场的运作能力&#xff0…

HTML静态网页成品作业(HTML+CSS)——家乡广州介绍设计制作(5个页面)

&#x1f389;不定期分享源码&#xff0c;关注不丢失哦 文章目录 一、作品介绍二、作品演示三、代码目录四、网站代码HTML部分代码 五、源码获取 一、作品介绍 &#x1f3f7;️本套采用HTMLCSS&#xff0c;未使用Javacsript代码&#xff0c;共有5个页面。 二、作品演示 三、代…

AI泳池溺水识别摄像机

AI泳池溺水识别摄像机是一种利用人工智能技术来监测和识别游泳池中溺水行为的智能监控设备。通过深度学习算法和图像识别技术&#xff0c;该摄像机能够实时捕捉游泳池的画面&#xff0c;自动分析水面动态和人员行为&#xff0c;判断是否有溺水事件发生&#xff0c;并及时发出警…

浅谈虚拟机下部分内网穿透功能实现方法

新钛云服已累计为您分享789篇技术干货 最近个人搭建服务器的情况有所增长&#xff0c;简单介绍一下一些可以使得服务器能被公网ip访问的方法。内网穿透一般用于将位于内部私有网络&#xff08;如家庭网络&#xff09;的服务暴露到公共网络&#xff08;如互联网&#xff09;上&a…

Java解决完全二叉树的节点个数

Java解决完全二叉树的节点个数 01 题目 给你一棵 完全二叉树 的根节点 root &#xff0c;求出该树的节点个数。 完全二叉树 的定义如下&#xff1a;在完全二叉树中&#xff0c;除了最底层节点可能没填满外&#xff0c;其余每层节点数都达到最大值&#xff0c;并且最下面一层的…

java集合框架——Map集合概述

前言&#xff1a; 之前接触了单列合集&#xff0c;现在又接触了双列合集。整理下心得&#xff0c;打好基础&#xff0c;daydayup&#xff01;&#xff01; Map集合 Map集合称为双列集合&#xff0c;也被称为“键值对集合”。格式&#xff1a;{key1value1,key2value2...}&#…

4-如何进行细分市场分析- 04 案例分析 健身房行业投资项目

现在运用前面学过的如何进行细分市场分析的1、2 、3 &#xff0c;以健身房行业投资项目为例来进行细分市场的分析&#xff1a;首先是画行业的产业链&#xff0c;如下图&#xff0c;注意其中的关键节点&#xff0c; 接着对市场竞争者进行进行细分和特征分析&#xff0c;确定主要…

docker引擎

目录 一、Docker引擎发展历程 二、docker引擎架构 三、docker引擎分类 四、docker引擎安装 4.1安装条件 4.2 使用rpm存储库安装 4.2.1设置存储库 4.2.2安装docker引擎 4.2.3启动docker,并设置docker开机自启动 五、卸载docker引擎 5.1.卸载 Docker 引擎、CLI、conta…

python二级备考(2)-简单应用题

第1套 使用turtle库的turtle. right()函数和turtle.fd()函数绘制一个菱形&#xff0c;边长为200像素&#xff0c;4个内角度数为2个60度和2个120度 键盘输入一组人员的姓名、性别、年龄等信息&#xff0c;信息间采用空格分隔&#xff0c;每人一行&#xff0c;空行回车结束录入&a…

无人机机载频谱监测方案助力空中频谱监测与干扰排查

作者介绍 一、方案背景 频谱资源是通信最重要的资产之一&#xff0c;随着宽带无线业务的快速增长&#xff0c;对频率资源的需求大幅增加。未来频率资源的供需矛盾将非常突出&#xff0c;空中频谱环境也会越来越复杂&#xff0c;对于工程师来说&#xff0c;在复杂的电磁环境条件…

Unload-labs-pass-03

这里是设置了黑名单不能传.asp.aspx.php.jsp文件 $is_upload false; $msg null; if (isset($_POST[submit])) {if (file_exists(UPLOAD_PATH)) {$deny_ext array(.asp,.aspx,.php,.jsp);$file_name trim($_FILES[upload_file][name]);$file_name deldot($file_name);//删…