\(\text{Problem}\)

有一个有向完全图,所有的 \(u\) 到 \(v\) 的边权为 \(a_u\)

修改 \(m\) 此有向边边权,求最终图上两两点对的最短路之和

\(1\le n \le 10^5,1\le m \le 3000,1\le a_u \le 10^6\)

\(\text{Solution}\)

好题

如果没有修改边,那么 \(u\) 到任意一点的最短路为 \(a_u\)

有修改边,注意到 \(m\) 相对 \(n\) 很小,也就是说涉及的点很少,不妨称其为特殊点

显然特殊点个数最多为 \(O(m)\) 的,且特殊边也是 \(O(m)\) 的

考虑把特殊边连起来的点看成一个连通块(也就是视特殊边为无向边,把特殊点连起来)

我们导出这些特殊点构成的图,就是很多连通块的组成的图

这样再考虑两两点对间的最短路

无非分为特殊点到块内和到块外

\(1.\) 特殊点到块外就是特殊点到普通点和特殊点到不在此连通块内的特殊点

\(2.\) 特殊点到块内一定是特殊点到特殊点的最短路

先考虑 \(①\)

逐个考虑块内的点 \(x\) 到块外所有点的最短路

显然是此块内点 \(x\) 到此块内其它点 \(y\) 再到外面

即 \(dis(x,y)+a_y\) 的最小值

所以 \(①\) 贡献的最短路和为 \((n-cnt) \cdot min\)

再考虑 \(②\)

通过某种手段求出块内全源最短路,将这些 \(dis\) 加起来即可

有特殊边,有普通边,普通边是形如 \(a_u\) 的只和此端点有关

枚举起点,用线段树维护 \(dis\)

特殊边单点修改松弛,特殊边没被影响过的点用普通边松弛,这些点分散在多个区间,线段树上区间修改即可

然后就完成了,确实有点麻烦,但思路很清晰

\(\text{Code}\)

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#define ls (p << 1)
#define rs (ls | 1)
#define re register
using namespace std;
typedef long long LL; const int N = 1e5 + 5;
const LL INF = 1e15;
int n, m, a[N], id[N], Q[N], cnt, tot, Tot, bz[N], h[N], H[N], color;
LL dis[N];
vector<int> d[N];
struct edge{int to, nxt, w;}e[N];
inline void add_edge(int x, int y, int z){e[++tot] = edge{y, h[x], z}, h[x] = tot;}
struct Edge{int to, nxt;}E[N];
inline void add_Edge(int x, int y){E[++Tot] = Edge{y, H[x]}, H[x] = Tot;}
struct node{int x; LL s;}b[N];
inline node Min(node a, node b){return (a.s <= b.s ? a : b);}
inline bool cmp(node a, node b){return a.s < b.s;} inline void read(int &x)
{
x = 0; char ch = getchar(); int f = 1;
for(; !isdigit(ch); f = (ch == '-' ? -1 : f), ch = getchar());
for(; isdigit(ch); x = (x<<3) + (x<<1) + (ch^48), ch = getchar());
x *= f;
} void dfs(int x)
{
bz[x] = color, Q[++cnt] = x;
for(re int i = H[x]; i; i = E[i].nxt) if (!bz[E[i].to]) dfs(E[i].to);
} LL tag[N >> 1], Mn[N >> 1]; int Mp[N >> 1];
inline void pushup(int p)
{
if (Mn[ls] <= Mn[rs]) Mn[p] = Mn[ls], Mp[p] = Mp[ls];
else Mn[p] = Mn[rs], Mp[p] = Mp[rs];
}
void build(int p, int l, int r)
{
tag[p] = Mn[p] = INF;
if (l == r) return void(Mp[p] = l);
int mid = l + r >> 1;
build(ls, l, mid), build(rs, mid + 1, r), pushup(p);
}
inline void pushdown(int p)
{
if (tag[p] == INF) return;
if (Mn[ls] != INF + 1) Mn[ls] = min(Mn[ls], tag[p]), tag[ls] = min(tag[ls], tag[p]);
if (Mn[rs] != INF + 1) Mn[rs] = min(Mn[rs], tag[p]), tag[rs] = min(tag[rs], tag[p]);
tag[p] = INF;
}
void modify(int p, int l, int r, int tl, int tr, LL v)
{
if (tl > r || tr < l || v >= tag[p]) return;
if (tl <= l && r <= tr)
{
if (Mn[p] != INF + 1) Mn[p] = min(Mn[p], v), tag[p] = min(tag[p], v);
return;
}
pushdown(p);
int mid = l + r >> 1;
if (tl <= mid) modify(ls, l, mid, tl, tr, v);
if (tr > mid) modify(rs, mid + 1, r, tl, tr, v);
pushup(p);
}
void pushflag(int p, int l, int r, int x)
{
if (l == r) return void(Mn[p] = tag[p] = INF + 1);
pushdown(p);
int mid = l + r >> 1;
if (x <= mid) pushflag(ls, l, mid, x);
else pushflag(rs, mid + 1, r, x);
pushup(p);
} void solve()
{
LL ans = 0, lst = 0;
for(re int i = 1; i <= n; i++)
if (!bz[i])
{
cnt = 0, ++color, dfs(i), sort(Q + 1, Q + cnt + 1);
int r = 1;
while (bz[b[r].x] == color && r <= n) ++r;
for(re int l = 1; l <= cnt; l++) id[Q[l]] = l;
for(re int l = 1; l <= cnt; l++)
{
build(1, 1, cnt), modify(1, 1, cnt, l, l, 0);
for(re int j = 1; j <= cnt; j++)
{
node now = node{Mp[1], Mn[1]};
for(re int k = h[Q[now.x]]; k; k = e[k].nxt) modify(1, 1, cnt, id[e[k].to], id[e[k].to], now.s + e[k].w);
if (d[Q[now.x]].size())
{
modify(1, 1, cnt, 1, id[d[Q[now.x]][0]] - 1, now.s + a[Q[now.x]]);
for(re int k = 1; k < d[Q[now.x]].size(); k++)
modify(1, 1, cnt, id[d[Q[now.x]][k - 1]] + 1, id[d[Q[now.x]][k]] - 1, now.s + a[Q[now.x]]);
modify(1, 1, cnt, id[d[Q[now.x]][d[Q[now.x]].size() - 1]] + 1, cnt, now.s + a[Q[now.x]]);
}
else modify(1, 1, cnt, 1, cnt, now.s + a[Q[now.x]]);
if (r <= n) modify(1, 1, cnt, 1, cnt, now.s + a[Q[now.x]] + b[r].s);
ans += (dis[now.x] = now.s), pushflag(1, 1, cnt, now.x);
}
LL mi = INF;
for(re int j = 1; j <= cnt; j++) mi = min(mi, dis[j] + a[Q[j]]);
ans += mi * (n - cnt);
}
}
printf("%lld\n", ans);
} int main()
{
freopen("happybean.in", "r", stdin), freopen("happybean.out", "w", stdout);
read(n), read(m);
for(re int i = 1; i <= n; i++) read(a[i]), b[i].x = i, b[i].s = a[i]; sort(b + 1, b + n + 1, cmp);
for(re int i = 1, x, y, z; i <= m; i++)
read(x), read(y), read(z), add_edge(x, y, z), d[x].push_back(y), add_Edge(x, y), add_Edge(y, x);
for(re int i = 1; i <= n; i++) sort(d[i].begin(), d[i].end());
solve();
}

JZOJ 7377.欢乐豆的更多相关文章

  1. (jzoj snow的追寻)线段树维护树的直径

    jzoj snow的追寻 DFS序上搞 合并暴力和,记录最长链和当前最远点,距离跑LCA # include <stdio.h> # include <stdlib.h> # ...

  2. [jzoj]3506.【NOIP2013模拟11.4A组】善良的精灵(fairy)(深度优先生成树)

    Link https://jzoj.net/senior/#main/show/3506 Description 从前有一个善良的精灵. 一天,一个年轻人B找到她并请他预言他的未来.这个精灵透过他的水 ...

  3. [jzoj]3468.【NOIP2013模拟联考7】OSU!(osu)

    Link https://jzoj.net/senior/#main/show/3468 Description osu 是一款群众喜闻乐见的休闲软件. 我们可以把osu的规则简化与改编成以下的样子: ...

  4. [jzoj]5478.【NOIP2017提高组正式赛】列队

    Link https://jzoj.net/senior/#main/show/5478 Description Sylvia 是一个热爱学习的女孩子.       前段时间,Sylvia 参加了学校 ...

  5. [jzoj]1115.【HNOI2008】GT考试

    Link https://jzoj.net/senior/#main/show/1115 Description 申准备报名参加GT考试,准考证号为n位数X1X2X3...Xn-1Xn(0<=X ...

  6. [jzoj]2538.【NOIP2009TG】Hankson 的趣味题

    Link https://jzoj.net/senior/#main/show/2538 Description Hanks 博士是BT (Bio-Tech,生物技术) 领域的知名专家,他的儿子名叫H ...

  7. [jzoj]4216.【NOIP2015模拟9.12】平方和

    Link https://jzoj.net/senior/#main/show/4216 Description 给出一个N个整数构成的序列,有M次操作,每次操作有一下三种: ①Insert Y X, ...

  8. [jzoj]2938.【NOIP2012模拟8.9】分割田地

    Link https://jzoj.net/senior/#main/show/2938 Description 地主某君有一块由2×n个栅格组成的土地,有k个儿子,现在地主快要终老了,要把这些土地分 ...

  9. [jzoj]2505.【NOIP2011模拟7.29】藤原妹红

    Link https://jzoj.net/senior/#main/show/2505 Description 在幻想乡,藤原妹红是拥有不老不死能力的人类.虽然不喜欢与人们交流,妹红仍然保护着误入迷 ...

  10. [jzoj]3875.【NOIP2014八校联考第4场第2试10.20】星球联盟(alliance)

    Link https://jzoj.net/senior/#main/show/3875 Problem 在遥远的S星系中一共有N个星球,编号为1…N.其中的一些星球决定组成联盟,以方便相互间的交流. ...

随机推荐

  1. 研究光度立体法阶段性小结和优化(可20ms获取4个2500*2000灰度图的Normal Map)。

    这个东西是我接触的第一个非2D方面的算法,到目前为止其实也没有完全搞定,不过可能短时间内也无法突破.先把能搞定的搞定吧. 这个东西也有一大堆参考资料,不过呢,搜来搜去其实也就那些同样的东西,个人觉得就 ...

  2. Go 的windows安装与环境配置

    1.请前往go的官网下载安装包:https://golang.org/dl/ 安装你如果C盘够大比较土豪就一路next即可,在这里小编穷就安装到了D:\Program Files\Go 2.环境变量配 ...

  3. RocketMQ系列-搭建Namesrv源码调试环境

    RocketMQ系列-搭建Namesrv源码调试环境 在学习任何一个技术框架的时候,我们通常都是先了解是什么,有什么作用.解决什么问题.设计亮点和设计思想是什么:当然对于技术学习上来说,这只是纸上谈兵 ...

  4. 使用.NET7和C#11打造最快的序列化程序-以MemoryPack为例

    译者注 本文是一篇不可多得的好文,MemoryPack 的作者 neuecc 大佬通过本文解释了他是如何将序列化程序性能提升到极致的:其中从很多方面(可变长度.字符串.集合等)解释了一些性能优化的技巧 ...

  5. 【SQL进阶】【分步写、联合各自排序、TIMESTAMPDIFF时间比较】Day04:多表查询

    〇.内容 时间比较2-2 联合结果各自排序 查询列和GROUP BY 一.嵌套子查询 1.月均完成试卷数不小于3的用户爱作答的类别 自己的答案[错误]: SELECT tag, COUNT(A.sta ...

  6. MetaTown:一个可以自己构建数字资产的平台

    摘要:华为云Solution as Code重磅推出<基于MetaTown构建数字资产平台>解决方案. 本文分享自华为云社区<基于MetaTown构建数字资产平台>,作者: 阿 ...

  7. 微软宣布 S2C2F 已被 OpenSSF 采用

    开源供应链安全对大多数 IT 领导者来说是个日益严峻的挑战,围绕确保开发人员在构建软件时如何使用和管理开源软件 (OSS) 依赖项的稳健策略至关重要.Microsoft 发布安全供应链消费框架 (S2 ...

  8. <三>function函数对象类型的应用示例

    std::function是一组函数对象包装类的模板,实现了一个泛型的回调机制.function与函数指针比较相似,优点在于它允许用户在目标的实现上拥有更大的弹性,即目标既可以是普通函数,也可以是函数 ...

  9. Kafka技术专题之「性能调优篇」消息队列服务端出现内存溢出OOM以及相关性能调优实战分析

    内存问题 本篇文章介绍Kafka处理大文件出现内存溢出 java.lang.OutOfMemoryError: Direct buffer memory,主要内容包括基础应用.实用技巧.原理机制等方面 ...

  10. 记一次InputStream流读取不完整留下的惨痛教训

    前言 首先,问问大家下面这段流读取的代码是否存在问题呢? inputStream = .... try { // 根据inputStream的长度创建字节数组 byte[] arrayOfByte = ...