\(\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. 解决linux mint内置无线网卡失效问题

    前言 同学安装了linux mint,但是内置的无线网卡失效,只能通过有线网卡连接,经过查询得到不是缺少驱动的问题,是内核不支持 解决办法 sudo apt install linux-generic ...

  2. 记一次windows10电脑连上wifi无法上网的解决问题

    前言 今天下午同学的电脑能连上wifi,但是却上不了互联网 开始思考 首先想到的肯定是WiFi驱动问题,但是wifi能连上大部分的原因可能就不是驱动问题了,为了彻底排除这个因素,我用到了我的usb网卡 ...

  3. SDK怎么测试?俺不会啊

    转载请注明出处️ 作者:测试蔡坨坨 原文链接:caituotuo.top/7bc8d1c8.html 你好,我是测试蔡坨坨. 众所周知,在云产品和SaaS蓬勃发展的当下,企业中有许多系统和环节都是依赖 ...

  4. Python Excel 处理模块 : OpenPyXL

    OpenPyXL模块使用方法 以下是介绍OpenPyXL的基本使用,不涉及样式和合并单元格的跨行操作 一般来说,对于大名鼎鼎的xlrd,xlwt和xlutils三个模块,Excel操作有3个基本状态 ...

  5. 跨机房ES同步实战

    作者:谢泽华 背景 众所周知单个机房在出现不可抗拒的问题(如断电.断网等因素)时,会导致无法正常提供服务,会对业务造成潜在的损失.所以在协同办公领域,一种可以基于同城或异地多活机制的高可用设计,在保障 ...

  6. 【LeetCode】剑指 Offer 30. 包含min函数的栈

    题目描述 定义栈的数据结构,请在该类型中实现一个能够得到栈的最小元素的 min 函数在该栈中,调用 min.push 及 pop 的时间复杂度都是 O(1). 思路 最初看到O(1)复杂度的时候,就想 ...

  7. 安装es客户端软件elasticsearch-head

    安装ElasticSearch插件 一 Head插件介绍 elasticsearch-head是elasticsearch的一款可视化工具,依赖于node.js ,所以需要先安装node.js 二 安 ...

  8. 周结之json补充、正则re模块、hashlib模块、logging模块

    周结 目录 周结 json补充 正则表达式 re模块 第三方模块的下载 request模块 办公自动化openpyxl模块 hashlib加密模块 subprocess模块 logging日志模块 j ...

  9. 重学c#系列——元组 [三十一]

    前言 元组并不是c# 7.0的东西,早之前就有,叫做tuple.7.0加了valuetuple. 来看下元组吧,主要一些注意的地方. 正文 为什么在7.0 之前,元组用的不多呢? 因为tuple 在代 ...

  10. 使用Git提交代码

    目录 1.提交前准备工作 2.代码提交步骤 3.从git上面拉代码 4.Git变更集 5.参考资料 1.提交前准备工作 首先去git官网下载git工具(Git GUI Here.Git Bash He ...