LOJ #10134. 「一本通 4.4 练习 1」Dis


分析

根据数据范围分析一下复杂度,Floyd和dj算法都必爆。

发现题目说的是树,还是边还是双向的(树本身就是无向的,连通无回路的无向图叫做无向树,简称树。如果题目说了树,那么默认边就是双向的),也没指明根节点,那么就是无根树,任选一个节点当根节点。

思路

是树的话就简单了,任意两点之间的最短距离很容易想到最近公共祖先,x到LCA的距离加上y到LCA的距离就是最短距离。

考虑在LCA预处理的dfs里面加上dis数组维护每个节点到根节点的距离。

那么x,y两点的最短距离就是dis[x]+dis[y]-2*dis[lca(x,y)]

AC代码

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

inline int read(){
    int x=0;char c=getchar();
    while(c<48 or c>57)c=getchar();
    while(c>=48 and c<=57)x=(x<<3)+(x<<1)+(c xor 48),c=getchar();
    return x;
}

using pii=pair<int,int>;
const int N=1e4+5;
int n,m,lg[N],d[N],f[N][15],dis[N];
vector<pii>e[N];
bitset<N>vis;

void dfs(int now,int fa){
    if(vis[now])return;//使用vector别忘了加vis,不然会访问父节点
    vis[now]=true;
    f[now][0]=fa;
    d[now]=d[fa]+1;
    for(int i=1;i<=lg[d[now]];++i)
        f[now][i]=f[f[now][i-1]][i-1];
    for(auto i:e[now]){
        if(!vis[i.second]){
            dis[i.second]=dis[now]+i.first;
            dfs(i.second,now);
        }
    }
}
int lca(int x,int y){
    if(d[x]<d[y])swap(x,y);
    while(d[x]>d[y])x=f[x][lg[d[x]-d[y]]-1];
    if(x==y)return x;
    for(int i=lg[d[x]];i>=0;--i)
        if(f[x][i]!=f[y][i]){
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}

int main(){
    ios::sync_with_stdio(false);
    n=read(),m=read();
    for(int i=1,x,y,k;i<=n-1;++i){
        x=read(),y=read(),k=read();
        e[x].push_back({k,y});
        e[y].push_back({k,x});
    }

    for(int i=1;i<=n;++i)
        lg[i]=log(i)/log(2)+1;
    dfs(1,1);

    for(int i=1,x,y;i<=m;++i){
        x=read(),y=read();
        cout<<dis[x]+dis[y]-2*dis[lca(x,y)]<<endl;
    }
    return 0;
}

倍增LCA代码细节有点多,被卡了两发。

1. d[x]>d[y]跳到同一深度之后先判断是不是到一个点了,是就直接返回。

2. 往上跳的时候是f[x][lg[d[x]-d[y]]-1],因为预处理的时候lg加了1

另外还有一道升级版#2491. 「BJOI2018」求和 - 题目 - LibreOJ (loj.ac)

在洛谷也有收录P4427 [BJOI2018] 求和 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

做一题水两边真是太好啦qwq


前一题只需要开一个数组dis来维护,这里k的范围有50,所以要开dis[N][51],来预处理所有深度的k次方,因为要取模所以会用到快速幂,注意根节点1的深度是0,特判返回值。

因为模数比较大别忘了开long long。

快速幂

int qkpow(int a,int k){
    int res=1;
    if(a==0)return 0;//特判0
    while(k){
        if(k&1)res*=a;
        k>>=1;
        a*=a;
        a%=MOD;
        res%=MOD;
    }
    return res;
}

预处理

    //预处理深度i^k次
    for(int i=0;i<N;++i){
        for(int k=1;k<=50;++k){
            a[i][k]= qkpow(i,k);
        }
    }

    d[1]=-1;//这里为-1和我的dfs用法有关
    for(int i=1;i<=n;++i)
        lg[i]=log(i)/log(2)+1;

大法师

void dfs(int now,int fa){
    if(vis[now])return;
    vis[now]=true;
    d[now]=d[fa]+1;
    for(int j=1;j<=50;++j){
        p[now][j]=p[fa][j]+a[d[now]][j];//子节点的j次方前缀和
        p[now][j]%=MOD;
    }
    f[now][0]=fa;
    for(int i=1;i<=lg[d[now]];++i)
        f[now][i]=f[f[now][i-1]][i-1];
    for(auto i:e[now]){
        dfs(i,now);
    }
}

LCA函数部分是一样的就不搬过来了。

这道题是点的前缀和,和前一题边的前缀和不一样。

边和只要减去两倍的LCA就行了,但是点和我们要算上LCA的值,所以是减去LCA和LCA的父节点。

注意

因为最终答案涉及了取模中减法,相减之后可能答案为负数,需要加上MOD再模上MOD。

AC代码

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

inline int read(){
    int x=0;char c=getchar();
    while(c<48 or c>57)c=getchar();
    while(c>=48 and c<=57)x=(x<<3)+(x<<1)+(c xor 48),c=getchar();
    return x;
}

const int N=3e5+5,MOD=998244353;
int n,m,d[N],f[N][20],lg[N],a[N][51],p[N][51];
vector<int>e[N];
bitset<N>vis;

int qkpow(int a,int k){
    int res=1;
    if(a==0)return 0;//特判0
    while(k){
        if(k&1)res*=a;
        k>>=1;
        a*=a;
        a%=MOD;
        res%=MOD;
    }
    return res;
}
void dfs(int now,int fa){
    if(vis[now])return;
    vis[now]=true;
    d[now]=d[fa]+1;
    for(int j=1;j<=50;++j){
        p[now][j]=p[fa][j]+a[d[now]][j];//子节点的j次方前缀和
        p[now][j]%=MOD;
    }
    f[now][0]=fa;
    for(int i=1;i<=lg[d[now]];++i)
        f[now][i]=f[f[now][i-1]][i-1];
    for(auto i:e[now]){
        dfs(i,now);
    }
}
int lca(int x,int y){
    if(d[x]<d[y])swap(x,y);
    while(d[x]>d[y])x=f[x][lg[d[x]-d[y]]-1];
    if(x==y)return x;
    for(int i=lg[d[x]];i>=0;--i)
        if(f[x][i]!=f[y][i]){
            x=f[x][i];
            y=f[y][i];
        }
    return f[x][0];
}

signed main(){
    ios::sync_with_stdio(false);
    n=read();
    for(int i=1,x,y;i<=n-1;++i){
        x=read(),y=read();
        e[x].push_back(y);
        e[y].push_back(x);
    }

    //预处理深度i^k次
    for(int i=0;i<N;++i){
        for(int k=1;k<=50;++k){
            a[i][k]= qkpow(i,k);
        }
    }

    d[1]=-1;
    for(int i=1;i<=n;++i)
        lg[i]=log(i)/log(2)+1;
    dfs(1,1);

    m=read();
    for(int i=1,x,y,k,LCA;i<=m;++i){
        x=read(),y=read(),k=read();
        LCA=lca(x,y);
        cout<<((p[x][k]+p[y][k]-p[LCA][k]-p[f[LCA][0]][k])%MOD+MOD)%MOD<<endl;
        //警惕模运算带来的坑
    }
    return 0;
}

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

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

相关文章

优思学院|现代质量管理实践与六西格玛方法论如何融合?

企业要解决质量问题必然需要涉及管理&#xff0c;然而&#xff0c;如果仅仅将六西格玛法视为一种质量管理方法&#xff0c;必定会导致六西格玛管理法的失败。六西格玛法是一种具有特定战略性的管理方法&#xff0c;它涉及到市场、顾客、产品、服务、流程、质量、价值链以及财务…

利用多核的Rust快速Merkle tree

1. 引言 利用多核的Rust快速Merkle tree&#xff0c;开源代码见&#xff1a; https://github.com/anoushk1234/fast-merkle-tree&#xff08;Rust&#xff09; 其具有如下属性&#xff1a; 可调整为任意高度构建root复杂度为O(n)提供了插入和获取叶子节点的方法获取某叶子节…

centos7 利用nc命令探测某个tcp端口是否在监听

脚本 # 安装nc yum install -y ncnc -vz 192.168.3.128 60001 if [ $? -eq 0 ]; thenecho "tcp succeed" elseecho "tcp failed" fi nc -vz 192.168.3.128 60001 探测192.168.3.128服务器上60001 tcp端口, -vz说明是探测TCP的 端口开启的情况 执行…

用不用Microsoft Defender是你的自由,但不用最好也得有替代品

Microsoft Defender是预装在Windows 11操作系统上的重要安全工具。安全套件已完全集成到操作系统中&#xff0c;以保护你的系统免受恶意软件的攻击&#xff0c;但并不是每个人都喜欢它。你是否更愿意安装另一种防病毒/反间谍软件&#xff0c;以将Microsoft Defender推向绝境&am…

ATA-304功率放大器的电子实验案例(案例合集)

ATA-304功率放大器凭借其优异的指标参数受到不少电子工程师的喜欢&#xff0c;其在电子实验中的应用也非常频繁&#xff0c;下面为大家整理出ATA-304功率放大器的应用案例合集&#xff0c;希望能对领域内各位工程师、研究人员有所帮助。 案例一&#xff1a;ATA-304功率放大器在…

并行与分布式 第4章 数据级并行:向量体系结构和GPU

文章目录 并行与分布式 第4章 数据级并行&#xff1a;向量体系结构和GPU4.1 什么叫数据级并行4.1.1 数据级并行与SPMD4.1.2数据级并行——传统器件的问题4.1.3 数据级并行——向量体系结构和GPU 4.2 向量体系结构4.2.1 向量以及计算方式4.2.2 向量体系结构4.2.3 向量运算的执行…

如何在公网环境下使用内网穿透工具实现用ipad pro进行代码开发

文章目录 前言1. 本地环境配置2. 内网穿透2.1 安装cpolar内网穿透(支持一键自动安装脚本)2.2 创建HTTP隧道 3. 测试远程访问4. 配置固定二级子域名4.1 保留二级子域名4.2 配置二级子域名 5. 测试使用固定二级子域名远程访问6. iPad通过软件远程vscode6.1 创建TCP隧道 7. ipad远…

解锁数据库运维秘籍:掌握AntDB-T动态共享内存,提升进程间通信效率

动态共享内存是AntDB数据库通信的重要手段&#xff0c;本文主要阐述AntDB-T数据库动态共享内存的实现原理、实现方式与使用方法。 AntDB-T数据库是一款企业级通用分布式关系型数据库&#xff0c;其数据库内核是基于进程模型实现的&#xff0c;因此进程间通信&#xff08;IPC&am…

撸源代码破冰杀手锏(一):Spring Security系列

一: 禅悟人生,码砖破冰感悟 二: Spring Security安全阐述 忙着去耍帅,后期补充完整.................

腾讯云服务器标准型S5实例CPU性能如何?配置特性说明

腾讯云服务器CVM标准型S5实例具有稳定的计算性能&#xff0c;CVM 2核2G S5活动优惠价格280.8元一年自带1M带宽&#xff0c;15个月313.2元、2核4G配置748.2元15个月&#xff0c;CPU内存配置还可以选择4核8G、8核16G等配置&#xff0c;公网带宽可选1M、3M、5M或10M&#xff0c;腾…

日期格式转化成星期几部署到linux显示英文

异常收集 原因&#xff1a;解决办法仰天大笑出门去&#xff0c;我辈岂是蓬蒿人 传入一个时间获取这个时间对应的是星期几&#xff0c;在开发环境&#xff08;window系统&#xff09;中显示为星期几&#xff0c;部署到服务器&#xff08;linux系统&#xff09;中会显示英文的时间…

什么是单片机?聊聊它的历史

前言 1946年2月15日&#xff0c;第一台电子数字计算机 ENIAC问世&#xff0c;这标志着计算机时代的到来。 ENIAC 是电子管计算机&#xff0c;时钟频率虽然仅有 100 kHz&#xff0c;但能在1s 的时间内完成 5000 次加法运算。与现代的计算机相比&#xff0c;ENIAC有许多不足&am…

腾讯云标准型s5和s6有什么区别?CPU处理器有差异吗?

腾讯云服务器CVM标准型S5和S6有什么区别&#xff1f;都是标准型云服务器&#xff0c;标准型S5是次新一代云服务器规格&#xff0c;标准型S6是最新一代的云服务器&#xff0c;S6实例的CPU处理器主频性能要高于S5实例&#xff0c;同CPU内存配置下的标准型S6实例要比S5实例性能更好…

KyLin离线安装OceanBase

去OceanBase下载若干文件 1 首先安装ob-deploy-2.3.1-2.el7.x86_64.rpm rpm -ivh ob-deploy-2.3.1-2.el7.x86_64.rpm# 运行此命令的时候他会报错 RPM should not be used directly install RPM packages, use Alien instead! 这个需要用Alien去转换为deb的包&#xff0c;不…

Linux中,查看Tomcat版本、如何查看Tomcat版本

方法 在tomcat的bin目录下&#xff0c;执行version.sh命令即可 结果

Pytorch完整的模型训练套路

Pytorch完整的模型训练套路 文章目录 Pytorch完整的模型训练套路以CIFAR10为例实践 数据集加载步骤 使用适当的库加载数据集&#xff0c;例如torchvision、TensorFlow的tf.data等。 将数据集分为训练集和测试集&#xff0c;并进行必要的预处理&#xff0c;如归一化、数据增强等…

桌面运维。

Windows运行命令&#xff1a; color 01/02切换字符颜色cls 清屏ipconfig 设备的ip信息ipconfig /all 设备ip的所有信息 破解系统密码&#xff1a; 进PE系统&#xff0c;使用里面的工具破解 vmware workstation安装 网卡 网卡&#xff1a;ncpa.cpl window远程控制 mstsc …

【JavaEE】Spring核心与设计思想(控制反转式程序演示、IoC、DI)

一、什么是Spring&#xff1f; 通常所说的 Spring 指的是 Spring Framework&#xff08;Spring 框架&#xff09;&#xff0c;它是⼀个开源框架&#xff0c;有着活跃⽽庞⼤的社区&#xff0c;这就是它之所以能⻓久不衰的原因。Spring ⽀持⼴泛的应⽤场景&#xff0c;它可以让 …

人工智能对我们的生活影响有多大

随着科技的飞速发展&#xff0c;人工智能已经渗透到我们生活的方方面面&#xff0c;并且越来越受到人们的关注。从智能语音助手到自动驾驶汽车&#xff0c;从智能家居系统到医疗诊断&#xff0c;人工智能技术正在改变着我们的生活方式。那么&#xff0c;人工智能对我们的生活影…

【C++上层应用】5. 文件和流

文章目录 【 1. 打开文件 】1.1 open 函数1.2 open 多种模式的结合使用 【 2. 关闭文件 】【 3. 写入 & 读取文件 】【 4. 文件位置指针 】 和 iostream 库中的 cin 标准输入流和 cout 标准输出流类似&#xff0c;C中另一个库 fstream 也存在文件的读取流和标准写入流。fst…