P9481 [NOI2023] 贸易 题解
题目要求我们求出任意两点间最短路径之和,由于图比较特殊,除树边外只有祖先到其子树内的边,我们首先考虑最短路径有没有什么特殊性质。
注意到两点之间的最短路分为一下三种:
节点到其祖先的最短路:直接沿着树边向上走即可,否则一定会走多余的边,不是最优。
节点到其子树的最短路:此时最短路一定形如沿着树边走若干条边,再走一条非树边,走若干条树边如此交替进行,当然此处也可以连续走非树边。
两个节点没有祖先孩子关系的最短路:如果此时要从 \(u\) 点走到 \(v\) 点,由于图中没有横叉边,\(u\) 点必须要走到 \(\operatorname{lca}(u,v)\),否则一定无法通过非树边到 \(v\) 点,之后转为为从 \(\operatorname{lca}(u,v)\) 到 \(v\) 的第二类最短路。
这三条最短路都会经过 \(\operatorname{lca}(u,v)\),由于其唯一性,考虑枚举最近公共祖先统计答案,第二类是方便统计的,而此时第一类也已经被处理了,我们把第三类分为两部分:从 \(u\) 到 \(\operatorname{lca}(u,v)\) 和 从 \(\operatorname{lca}(u,v)\) 到 \(v\)。
第一段通过预处理即可解决,对于每个枚举到的 \(\operatorname{lca}\),由于树高是 \(\log\) 的,第二段路径所牵扯到的节点数也不会超过 \(N\log N\) 个,因此可以直接建反图暴力跑最短路统计,之后模仿点分治计算一遍即可。
代码中我对于每个 \(\operatorname{lca}\) 的子节点正序倒序分别枚举了一次,枚举到每颗子树时累加前面的子树走前半段,这颗子树走后半段的答案,即可保证不重不漏。
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#include<queue>
#define ll long long
#define N 700005
using namespace std;
const ll mod=998244353;
const ll inf=0x3f3f3f3f3f3f3f3f;
ll tot,dsum[N],dfn[N],ri[N],val[N],dis[N],vis[N],dep[N];
ll bel[N],siz[N],ans,ttp[N],sta[N],p,ct[N];
struct graph{
ll e,head[N],to[N],nex[N],edg[N];
void add(ll u,ll v,ll w){
to[++e]=v;nex[e]=head[u];head[u]=e;edg[e]=w;
}
void clear(){
for(ll i=1;i<=e;i++)head[i]=nex[i]=edg[i]=to[i]=0;
e=0;
}
}T,G;
struct edg{
ll u,v,w;
};
struct Node{
ll v,val;
bool operator <(const Node &x)const{
return val>x.val;
}
};
void adj(ll &x){
x=(((x%mod)+mod)%mod);
}
priority_queue<Node> q;
vector<edg> E[N];
void dfs(ll x){
dfn[x]=++tot;bel[tot]=x;siz[x]=1;
for(ll i=T.head[x];i;i=T.nex[i]){
ll v=T.to[i],w=T.edg[i];dep[v]=dep[x]+w;adj(dep[v]);dfs(v);
dsum[x]+=w*siz[v]+dsum[v];dsum[x]%=mod;
siz[x]+=siz[v];
}
ri[x]=tot;
}
void dij(ll s){
q.push((Node){s,0});dis[s]=0;
while(q.size()){
ll x=q.top().v;q.pop();if(vis[x]) continue;
vis[x]++;
for(ll i=G.head[x];i;i=G.nex[i]){
ll v=G.to[i],w=G.edg[i];
if(dis[v]>dis[x]+w){
dis[v]=dis[x]+w;
q.push((Node){v,dis[v]});
}
}
}
}
void dfs2(ll x){
G.clear();
for(ll i=dfn[x];i<=ri[x];i++){
dis[i]=inf;vis[i]=0;ans+=dep[bel[i]]-dep[x];adj(ans);
for(ll j=0;j<E[bel[i]].size();j++){
G.add(dfn[E[bel[i]][j].u],dfn[E[bel[i]][j].v],E[bel[i]][j].w);
}
G.add(dfn[bel[i]],dfn[bel[i]/2],val[bel[i]]);
}
ll tmp=x,tmp2=x/2,sumdis=0,sumsiz=1,cnt=0,tp=0;
while(tmp2){
G.add(dfn[tmp],dfn[tmp2],val[tmp]);
vis[dfn[tmp]]=0;dis[dfn[tmp]]=inf;tmp=tmp2;tmp2/=2;
}
vis[1]=0;dis[1]=inf;dij(dfn[x]);tmp=x;p=0;
for(ll i=T.head[x];i;i=T.nex[i]){
sta[++p]=i;ll v=T.to[i];tp=0;cnt=0;
for(ll j=dfn[v];j<=ri[v];j++){
if(dis[j]!=inf){
tp+=dis[j];adj(tp);cnt++;
}
}
ttp[v]=tp;ct[v]=cnt;
ans+=((sumsiz*tp)%mod)+((cnt*sumdis)%mod);adj(ans);
sumsiz+=siz[v];adj(sumsiz);
sumdis+=dsum[v]+((T.edg[i]*siz[v])%mod);adj(sumdis);
}
sumsiz=sumdis=0;
for(ll i=p;i>=1;i--){
ll j=sta[i],v=T.to[j];tp=ttp[v];cnt=ct[v];
ans+=((sumsiz*tp)%mod)+((cnt*sumdis)%mod);adj(ans);
sumsiz+=siz[v];adj(sumsiz);
sumdis+=dsum[v]+((T.edg[j]*siz[v])%mod);adj(sumdis);
}
for(ll i=dfn[x];i<=ri[x];i++)G.head[i]=dis[i]=0;
while(tmp){G.head[dfn[tmp]]=0;dis[dfn[tmp]]=0;tmp/=2;}
for(ll i=T.head[x];i;i=T.nex[i])dfs2(T.to[i]);
}
ll read(){
ll 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<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int main(){
ll n,m,u,v,w;n=read();m=read();n=(1<<n)-1;
for(ll i=2;i<=n;i++){cin>>w;T.add((i/2),i,w);val[i]=w;}
for(ll i=1;i<=m;i++){
u=read();v=read();w=read();
E[v].push_back((edg){u,v,w});
}
dfs(1);dfs2(1);
cout<<ans;
}
P9481 [NOI2023] 贸易 题解的更多相关文章
- 「NOIP2009」最优贸易 题解
「NOIP2009」最优贸易 题解 题目TP门 题目描述 \(C\)国有\(n\)个大城市和\(m\)条道路,每条道路连接这\(n\)个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 ...
- 51NOD 1773:A国的贸易——题解
http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1773 参考1:FWT讲解 https://www.cnblogs.com ...
- NOIP 2009 最优贸易 题解
一道最短路的题,找一个买入和卖出相差最高的点即可,我们先以1为起点跑spfa,d1[x]不再表示距离而表示能够经过权值最小的节点的权值即 if(d1[y]>min(d1[x],price[y]) ...
- 洛谷 P1073 最优贸易 题解
题面 大家都是两遍SPFA吗?我这里就一遍dp啊: 首先判断对于一个点u,是否可以从一号点走到这里,并且可以从u走到n号点: 对于这样的点我们打上标记: 那么抛出水晶球的点一定是从打上标记的点中选出一 ...
- bzoj1205: [HNOI2005]星际贸易
题目链接 bzoj1205: [HNOI2005]星际贸易 题解 辣鸡题面,毁我青春 辣鸡题面,毁我青 辣鸡题面,毁我 辣鸡题面,毁 第一问,背包dp 第二问 问题转化为在一个序列上经过好多点走到终点 ...
- 【题解】洛谷P1073 [NOIP2009TG] 最优贸易(SPFA+分层图)
次元传送门:洛谷P1073 思路 一开始看题目嗅出了强连通分量的气息 但是嫌长没打 听机房做过的dalao说可以用分层图 从来没用过 就参考题解了解一下 因为每个城市可以走好几次 所以说我们可以在图上 ...
- 【luogu P1073 最优贸易】 题解
题目链接:https://www.luogu.org/problemnew/show/P1073 对于状态量相互影响的题目,分层图是个不错的想法. 考虑在题目中分为: 不交易: 直接从1到n出去,为0 ...
- 题解【luogu1073 最优贸易】
Solution 考虑原图是 DAG 时怎么做. 拓扑排序 + dp ,令 dp[i] 表示 \(1\) 到 \(i\) 的路径上最小的卖出价格.转移方程就是对每一个可以到达这个点的 dp 取个 mi ...
- noip2009提高组题解
NOIP2009题解 T1:潜伏者 题目大意:给出一段密文和破译后的明文,一个字母对应一个密文字母,要求破译一段密文,如果有矛盾或有未出现密文无法破译输出failed,否则输出明文. 思路:纯模拟题 ...
- 历年NOIP选题题解汇总
联赛前上vijos板刷往年联赛题,使用在线编辑编写代码,祝我rp++. 废话不多说,挑比较有意思的记一下. 题目是按照年份排序的,最早只到了03年. 有些题目因为 我还没写/很早之前写的忘了 所以就没 ...
随机推荐
- AutoCAD 2024下载及安装教程
安装教程 演示操作系统:Windows 11 *安装前请关闭所有杀毒软件,避免报错 1.解压[CAD2024.zip] 2.打开解压的[CAD2024]文件夹,打开[Setup]文件夹,运行[Setu ...
- 基于AIidlux平台的自动驾驶环境感知与智能预警
自动驾驶汽车又称为无人驾驶车,是一种需要驾驶员辅助或者完全不需操控的车辆. 自动驾驶分级: 自动驾驶系统的组成部分: 环境感知系统: 自动驾驶系统架构: 自动驾驶数据集: Aidlux的作用: YOL ...
- Tcpdump 使用指南
论网络数据包的分析,我首选wireshark,因为图形化界面直观明了.但如果遇到没有图形化显示的Linux环境,那么此时会使用tcpdump该是一件多么美好的事情. 网上关于tcpdump的介绍很多, ...
- [linux]常见内核TCP参数描述与配置
前言 所有的TCP/IP参数都位于/proc/sys/net目录下(请注意,对/proc/sys/net目录下内容的修改都是临时的,任何修改在系统重启后都会丢失),如果需要固化设置,则需要修改/etc ...
- php批量同步数据
php批量同步流程 首先分页获取数据 创建临时表 批量添加数据 备份原表 删除原表 修改临时表表名改为原表 代码 1 <?php 2 3 class Stock{ 4 5 private $da ...
- Godot无法响应鼠标点击等输入事件时,检查这些内容
注:本文以Godot 4.0 为基准,可能其他版本也能参考. 这是我用C#写项目时发现的,可能和gdscript使用者遇到的问题有一定区别. 如果你用Godot制作的游戏无法响应鼠标点击等输入事件,请 ...
- servlet系列:简介和基本使用以及工作流程
目录 一.简介 二.Servlet实现 三.基本使用 1.引入pom依赖 2.实现Servlet规范,重写service方法 3.配置web.xml 4.配置Tomcat 6.运行 四.Servlet ...
- 《SQL与数据库基础》21. 分库分表(一)
目录 分库分表(一) 拆分策略 垂直拆分 垂直分库 垂直分表 水平拆分 水平分库 水平分表 技术实现 MyCat概述 概念介绍 环境准备 目录介绍 MyCat入门 配置 分片配置(schema.xml ...
- ctypes使用浅谈
什么是ctypes: ctypes 是 Python 的一个标准库,用于与 C 语言进行交互.它提供了一组工具和函数,可以方便地调用动态链接库(DLL)或共享对象(SO)中的 C 函数,并处理 C 数 ...
- vue + canvas 实现九宮格手势解锁器
前言 专栏分享:vue2源码专栏,vue router源码专栏,玩具项目专栏,硬核推荐 欢迎各位 ITer 关注点赞收藏 此篇文章用于记录柏成从零开发一个canvas九宮格手势解锁器的历程,最终效果如 ...