题目链接

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

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

  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. 【原创】xenomai UDD介绍与UDD用户态驱动示例

    目录 xenomai UDD与用户态驱动示例 一.UDD介绍 二.UDD原理及框架 1. 内存映射 2. 中断处理 UDD与UIO的区别 3. linux UIO与xenomai UDD框架对比 3. ...

  2. 如何修改NuGet默认全局包文件夹的位置?

    由于一些历史原因,重装系统成为Windows用户解决疑难杂症的祖传手艺.受此影响,给硬盘分盘几乎成为了一种执念,少则C.D两个盘,夸张一点的5~6个盘的也不是没有. PS:macOS和Linux一直都 ...

  3. MAUI Blazor Android 输入框软键盘遮挡问题2.0

    前言 关于MAUI Blazor Android 输入框软键盘遮挡问题,之前的文章已经有了答案,MAUI Blazor Android 输入框软键盘遮挡问题 但是这个方案一直存在一点小的瑕疵 在小窗模 ...

  4. 【技术实战】Vue技术实战【四】

    需求实战一 效果展示 代码展示 <template> <ARow> <ACol> <a-statistic-countdown :value="de ...

  5. std::queue 中遇到释放内存错误的问题

    项目上有个需求要用到 std::queue 顺序处理消息事件 简单的示例如下: struct MyEvent { MyEvent() { event_ = CreateEvent(nullptr, 0 ...

  6. React: Warning: `value` prop on `input` should not be null.

    警告 解决方案 对value进行判断 修改后的效果 至此问题解决

  7. 给你推荐一款快速通过 typescript 生成 jsonschema 的包处理器

    theme: github fast-typescript-to-jsonschema Typescript 生成 jsonschema 数据插件 性能 案例 interface AAA { a: n ...

  8. 重返照片的原始世界:我为.NET打造的RAW照片解析利器

    重返照片的原始世界:我为.NET打造的RAW照片解析利器 如果你是我的老读者,你可能还记得,在2019年,我冒险进入了一片神秘的领域--用C#解析RAW格式的照片: 20191208 - 用.NET解 ...

  9. JavaScript中单例模式这样用

    如果希望自己的代码更优雅.可维护性更高以及更简洁,往往离不开设计模式这一解决方案. 在JS设计模式中,最核心的思想:封装变化(将变与不变分离,确保变化的部分灵活,不变的部分稳定). 单例模式 那么来说 ...

  10. Hadoop集群启动没有DataNode进程

    问题状况: 问题原因: 在启动Hadoop之前,进行了多次格式化,导致DataNode的ID发生了变化 解决方案: 我们可以删除从节点所有的DataNode资料,并重新格式化 解决流程 1.根据cor ...