【luogu CF1163F】Indecisive Taxi Fee(图论)(分类讨论)

Indecisive Taxi Fee

题目链接:luogu CF1163F

题目大意

给你一个无向图,每次改一条边的权值(每次都会变回来),问你 1~n 的最短路长度。

思路

考虑分类讨论,先找到最短路的路径,然后看修改的边在不在最短路上。

如果不在,要么还是原来的最短路,要么就是你这条边 (x,y)1x 的最短路加上你的新边权再加上 yn 的最短路。
然后 1,n 到所有点的最短路我们预处理出来就可以弄。

然后就是在最短路,那要么是原来的最短路优,要么是你新找一条最短路它不经过你改的这条边(就是把它删了跑最短路)。
发现只有这个新找路要求,考虑一下这条路的性质。

发现一定能找一条,它肯定是跟最短路有一个前缀,一个后缀,中间的部分不会跟最短路的边有交集。
因为有交集,假设分成两半,你把不是删了的边的那一半改成最短路,那更短或者一样啊。

然后你就看每条不在最短路上的边,如果要他走这条边作为最短路,它能代替那些最短路上的边。
那根据前面,代替的也是一个区间的。
于是考虑求这个区间。

对于每个点,你有一个 Li 表示最小的 x,使得 1i 的路上 ex 这条边是第一个不在最短路上的边
ei 是最短路的边)
Ri 表示最大的 x 使得 xn 的路上 ex 这条边是最后一个不在最短路上的边。
那这个我们可以 DP,一开始对于最短路上的点,有 Lx=i,Rx=iix 是第几个点)

然后你按从 1 开始的最短路树的顺序,和 n 开始的最短路树的顺序,分别 DP Li,Ri,就直接选不在最短路上的边,儿子跟它取 min,max 即可。
那求出来点,接着看边的,那就根据 Lx,Ry 确定一下 x,y,只要有区间就行那种,那这个就是那个区间了。
那怎么求所有边的答案呢?因为有很多个区间可以选。
会发现对于里面能替换掉的所有最短路上的边,替换之后走的距离都是一样的。

然后你考虑一个指针从左往右扫,最左侧放入,最右侧弹出,维护一个 multiset,每次答案就是最小值。
当然你用线段树搞也可以。

代码

#include<set> #include<queue> #include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N = 2e5 + 1000; struct node { ll x, to, nxt, id; }e[N << 1]; ll n, m, q, le[N], KK, dian[N], bian[N]; ll xxx[N], yyy[N], zzz[N], pl[N], ib[N]; ll L[N], R[N]; ll miss[N]; void add(ll x, ll y, ll z, ll id) { e[++KK] = (node){z, y, le[x], id}; le[x] = KK; } bool cant[N]; struct Work { ll S, fr[N], frid[N]; ll f[N]; bool in[N]; void work() { priority_queue <pair<ll, ll>, vector<pair<ll, ll> >, greater<pair<ll, ll> > > q; while (!q.empty()) q.pop(); memset(in, 0, sizeof(in)); memset(f, 0x3f, sizeof(f)); f[S] = 0; q.push(make_pair(0, S)); while (!q.empty()) { ll now = q.top().second; q.pop(); if (in[now]) continue; in[now] = 1; for (ll i = le[now]; i; i = e[i].nxt) if (!cant[e[i].id] && f[e[i].to] > f[now] + e[i].x) { f[e[i].to] = f[now] + e[i].x; fr[e[i].to] = now; frid[e[i].to] = e[i].id; q.push(make_pair(f[e[i].to], e[i].to)); } } } void get_road(ll T) { ll now = T; while (now != S) { cant[frid[now]] = 1; bian[++bian[0]] = frid[now]; dian[++dian[0]] = now; now = fr[now]; } dian[++dian[0]] = now; reverse(dian + 1, dian + dian[0] + 1); reverse(bian + 1, bian + bian[0] + 1); } }T1, Tn; bool cmp1(ll x, ll y) { return T1.f[x] < T1.f[y]; } bool cmpn(ll x, ll y) { return Tn.f[x] < Tn.f[y]; } multiset <ll> qq; vector <ll> up[N], down[N]; int main() { scanf("%lld %lld %lld", &n, &m, &q); for (ll i = 1; i <= m; i++) { ll x, y, z; scanf("%lld %lld %lld", &x, &y, &z); add(x, y, z, i); add(y, x, z, i); xxx[i] = x; yyy[i] = y; zzz[i] = z; } T1.S = 1; Tn.S = n; T1.work(); Tn.work(); T1.get_road(n); for (ll i = 1; i <= bian[0]; i++) ib[bian[i]] = i; memset(L, 0x3f, sizeof(L)); for (ll i = 1; i <= dian[0]; i++) L[dian[i]] = i, R[dian[i]] = i; for (ll i = 1; i <= n; i++) pl[i] = i; sort(pl + 1, pl + n + 1, cmp1); for (ll i = 1; i <= n; i++) { ll now = pl[i]; for (ll j = le[now]; j; j = e[j].nxt) if (!cant[e[j].id] && T1.f[e[j].to] == T1.f[now] + e[j].x) L[e[j].to] = min(L[e[j].to], L[now]); } sort(pl + 1, pl + n + 1, cmpn); for (ll i = 1; i <= n; i++) { ll now = pl[i]; for (ll j = le[now]; j; j = e[j].nxt) if (!cant[e[j].id] && Tn.f[e[j].to] == Tn.f[now] + e[j].x) R[e[j].to] = max(R[e[j].to], R[now]); } for (ll i = 1; i <= m; i++) if (!cant[i]) { ll x = xxx[i], y = yyy[i]; if (L[x] <= R[y] - 1) { ll val = T1.f[x] + zzz[i] + Tn.f[y]; up[L[x]].push_back(val); down[R[y] - 1].push_back(val); } swap(x, y); if (L[x] <= R[y] - 1) { ll val = T1.f[x] + zzz[i] + Tn.f[y]; up[L[x]].push_back(val); down[R[y] - 1].push_back(val); } } memset(miss, 0x3f, sizeof(miss)); for (ll i = 1; i <= dian[0]; i++) { for (ll j = 0; j < up[i].size(); j++) qq.insert(up[i][j]); if (!qq.empty()) miss[i] = *qq.begin(); for (ll j = 0; j < down[i].size(); j++) qq.erase(qq.find(down[i][j])); } while (q--) { ll x, y; scanf("%lld %lld", &x, &y); if (cant[x]) {//在最短路 printf("%lld\n", min(miss[ib[x]], T1.f[n] - zzz[x] + y)); } else {//不在最短路 printf("%lld\n", min(T1.f[n], min(T1.f[xxx[x]] + y + Tn.f[yyy[x]], T1.f[yyy[x]] + y + Tn.f[xxx[x]]))); } } return 0; }

__EOF__

本文作者あおいSakura
本文链接https://www.cnblogs.com/Sakura-TJH/p/luogu_CF1163F.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   あおいSakura  阅读(47)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示