题目链接

题目要求我们求出任意两点间最短路径之和,由于图比较特殊,除树边外只有祖先到其子树内的边,我们首先考虑最短路径有没有什么特殊性质。

注意到两点之间的最短路分为一下三种:

  1. 节点到其祖先的最短路:直接沿着树边向上走即可,否则一定会走多余的边,不是最优。

  2. 节点到其子树的最短路:此时最短路一定形如沿着树边走若干条边,再走一条非树边,走若干条树边如此交替进行,当然此处也可以连续走非树边。

  3. 两个节点没有祖先孩子关系的最短路:如果此时要从 \(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] 贸易 题解的更多相关文章

  1. 「NOIP2009」最优贸易 题解

    「NOIP2009」最优贸易 题解 题目TP门 题目描述 \(C\)国有\(n\)个大城市和\(m\)条道路,每条道路连接这\(n\)个城市中的某两个城市.任意两个城市之间最多只有一条道路直接相连.这 ...

  2. 51NOD 1773:A国的贸易——题解

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1773 参考1:FWT讲解 https://www.cnblogs.com ...

  3. NOIP 2009 最优贸易 题解

    一道最短路的题,找一个买入和卖出相差最高的点即可,我们先以1为起点跑spfa,d1[x]不再表示距离而表示能够经过权值最小的节点的权值即 if(d1[y]>min(d1[x],price[y]) ...

  4. 洛谷 P1073 最优贸易 题解

    题面 大家都是两遍SPFA吗?我这里就一遍dp啊: 首先判断对于一个点u,是否可以从一号点走到这里,并且可以从u走到n号点: 对于这样的点我们打上标记: 那么抛出水晶球的点一定是从打上标记的点中选出一 ...

  5. bzoj1205: [HNOI2005]星际贸易

    题目链接 bzoj1205: [HNOI2005]星际贸易 题解 辣鸡题面,毁我青春 辣鸡题面,毁我青 辣鸡题面,毁我 辣鸡题面,毁 第一问,背包dp 第二问 问题转化为在一个序列上经过好多点走到终点 ...

  6. 【题解】洛谷P1073 [NOIP2009TG] 最优贸易(SPFA+分层图)

    次元传送门:洛谷P1073 思路 一开始看题目嗅出了强连通分量的气息 但是嫌长没打 听机房做过的dalao说可以用分层图 从来没用过 就参考题解了解一下 因为每个城市可以走好几次 所以说我们可以在图上 ...

  7. 【luogu P1073 最优贸易】 题解

    题目链接:https://www.luogu.org/problemnew/show/P1073 对于状态量相互影响的题目,分层图是个不错的想法. 考虑在题目中分为: 不交易: 直接从1到n出去,为0 ...

  8. 题解【luogu1073 最优贸易】

    Solution 考虑原图是 DAG 时怎么做. 拓扑排序 + dp ,令 dp[i] 表示 \(1\) 到 \(i\) 的路径上最小的卖出价格.转移方程就是对每一个可以到达这个点的 dp 取个 mi ...

  9. noip2009提高组题解

    NOIP2009题解 T1:潜伏者 题目大意:给出一段密文和破译后的明文,一个字母对应一个密文字母,要求破译一段密文,如果有矛盾或有未出现密文无法破译输出failed,否则输出明文. 思路:纯模拟题 ...

  10. 历年NOIP选题题解汇总

    联赛前上vijos板刷往年联赛题,使用在线编辑编写代码,祝我rp++. 废话不多说,挑比较有意思的记一下. 题目是按照年份排序的,最早只到了03年. 有些题目因为 我还没写/很早之前写的忘了 所以就没 ...

随机推荐

  1. 2021级HAUT新生周赛题解汇总

    2021级HAUT新生周赛(一)题解@张君毅:第一场 2021级HAUT新生周赛(二)题解@李亚凯:第二场 2021级HAUT新生周赛(三)题解@李晨曦:第三场 2021级HAUT新生周赛(四)题解@ ...

  2. 2023河南省ICPC大学生程序设计竞赛-wh

    第一次出去比赛,首先感谢程老师选择我们新生更多的比赛机会,感谢! 在周六我们一起做了高铁出发取洛阳参加icpc河南省赛,不得不说洛阳师范学院确实环境很好看..在热身赛时,已经被泼了冷水,这C也太难了, ...

  3. C语言指针--指针中的const

    文章目录 前言 一.const 1.什么是const 2.const的使用 二.const修饰一级指针 1.const放在 `*` 左边 2.const在`*`右边 三.const修饰二级指针 1.c ...

  4. docker安装8版本elasticsearch遇到的问题FileSystemException

    docker安装8版本elasticsearch遇到的问题 Exception in thread "main" java.nio.file.FileSystemException ...

  5. Unity UGUI的Outline(描边)组件的介绍及使用

    Unity UGUI的Outline(描边)组件的介绍及使用 1. 什么是Outline(描边)组件? Outline(描边)组件是Unity UGUI中的一种特效组件,用于给UI元素添加描边效果.通 ...

  6. 解决npm install 报错 'proxy' config is set properly. See: 'npm help config'

    输入以下命令 npm config set proxy null npm config set https-proxy null 之后重新安装即可 文章参考 https://blog.csdn.net ...

  7. Kubernetes: Kubectl 源码分析

    0. 前言 kubectl 看了也有一段时间,期间写了两篇设计模式的文章,是时候对 kubectl 做个回顾了. 1. kubectl 入口:Cobra kubectl 是 kubernetes 的命 ...

  8. python教程 入门学习笔记 第2天 第一个python程序 代码规范 用默认的IDLE (Python GUI)编辑器编写

    四.第一个python程序 1.用默认的IDLE (Python GUI)编辑器编写 2.在新建文件中写代码,在初始窗口中编译运行 3.写完后保存为以.py扩展名的文件 4.按F5键执行,在初始窗口观 ...

  9. 《UNIX 传奇:历史与回忆》读后感

    <UNIX 传奇:历史与回忆> 是 bwk(Brian W. Kernighan)2019 年的新作,回忆了 UNIX 在大半个世纪的风雨历程,是一本引人入胜的书籍.通过对 UNIX 操作 ...

  10. 基于consul实现docker跨主机网络通信

    前言 IP: 192.168.0.10 192.168.0.11 系统版本:ubuntu 20.04 consul版本:1.11.1 官网下载地址: https://www.consul.io/dow ...