其他分享
首页 > 其他分享> > CF1163F Indecisive Taxi Fee

CF1163F Indecisive Taxi Fee

作者:互联网

洛谷题面

\(\rm update:\) 添加了代码。

题目大意

给你一个 \(n\) 个点,\(m\) 条边的无向图,每条边连接点 \(u, v\),并且有个长度 \(w\)。

有 \(q\) 次询问,每次询问给你一对 \(t, x\),表示仅当前询问下,将 \(t\) 这条边的长度修改为 \(x\),请你输出当前 \(1\) 到 \(n\) 的最短路长度。

题目分析

首先我们先用 \(\verb!Dijkstra!\) 求出从 \(1\) 开始的最短路 \(dis[i]\)。

然后接下来对于每次询问(我们注意到每次询问相互独立)我们可以分为 \(4\) 种情况:

本来就不在最短路径上,边权还变大了,答案不会变,还是 \(dis[n]\)。

假设这条边可以表示为 \((u,v)\),答案就是 \(\min\{dist(1,u)+dist(v,n)+x',dist(1,v)+dist(u,n)+x'\}\)。

\(dist(1,u),dist(1,v)\) 是等价于 \(dis[u],dis[v]\) 的,而 \(dist(u,n),dist(v,n)\) 呢?我们最开始也从 \(n\) 开始跑一遍最短路,存储到 \(dis'[i]\) 中就好了。 这样 \(dist(u,n),dist(v,n)\) 等价于 \(dis'[u],dis'[v]\)。

这个简单。本来就是最短路径了,边权还变小了,那么这条路肯定还在最短路径上。此时的答案是 \(dis[n]-x+x'\),\(x\) 是原权值,\(x'\) 是现权值。

不妨令最短路上的所有边的每个元素分别为 \(e_1,e_2,\cdots,e_k\)(连着的)。

引出结论:经过一条边 \((u,v)\) 的最短路径,\(1\to u\) 的最短路一定会经过一段 \(e\) 的前缀(可能为空),\(v\to n\) 的最短路一定会经过一段 \(e\) 的后缀(可能为空)。即 与最短路不重合的部分最多只有一段。

证明不难留作习题。

简单证明一下:

反证法。如果多于一段不重合,那么一条边不可能包含于多个不重合的段中,则其他段取最短路会更优。


对于每个不在最短路上的点 \(u\),设 \(1\to u\) 的最短路必经过的前缀为 \(e_1,e_2,\cdots,e_{L[u]}\),后缀是 \(e_{R[u]},\cdots,e_k\)。

问题转换为求不经过 \(e\) 上某条边的最短路长度是多少。

不经过 \((u,v)\) 时 \(1\to n\) 的最短路径长度,即不经过 \(e_{L[u]+1},\cdots,e_{R[v]-1}\) 的最短路径长度。

线段树求解,\([l,r]\) 表示不经过 \(e_l\sim e_r\) 的最短路的长度,然后拿经过 \((u,v)\) 的最短路长度 \(dis[u]+dis'[v]+x\) 更新线段树

代码

// Problem: CF1163F Indecisive Taxi Fee
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/CF1163F
// Memory Limit: 500 MB
// Time Limit: 2000 ms
// Date:2022-05-30 22:27
// 
// Powered by CP Editor (https://cpeditor.org)

#include <iostream>
#include <cstdio>
#include <climits>//need "INT_MAX","INT_MIN"
#include <cstring>//need "memset"
#include <numeric>
#include <algorithm>
#include <cmath>
#include <queue>
#include <utility>
#define int long long
#define enter putchar(10)
#define debug(c,que) std::cerr << #c << " = " << c << que
#define cek(c) puts(c)
#define blow(arr,st,ed,w) for(register int i = (st);i <= (ed); ++ i) std::cout << arr[i] << w;
#define speed_up() std::ios::sync_with_stdio(false),std::cin.tie(0),std::cout.tie(0)
#define mst(a,k) memset(a,k,sizeof(a))
#define stop return(0)
const int mod = 1e9 + 7;
inline int MOD(int x) {
	if(x < 0) x += mod;
	return x % mod;
}
namespace Newstd {
	inline int read() {
		int ret = 0,f = 0;char ch = getchar();
		while (!isdigit(ch)) {
			if(ch == '-') f = 1;
			ch = getchar();
		}
		while (isdigit(ch)) {
			ret = (ret << 3) + (ret << 1) + ch - 48;
			ch = getchar();
		}
		return f ? -ret : ret;
	}
	inline double double_read() {
		long long ret = 0,w = 1,aft = 0,dot = 0,num = 0;
		char ch = getchar();
		while (!isdigit(ch)) {
			if (ch == '-') w = -1;
			ch = getchar();
		}
		while (isdigit(ch) || ch == '.') {
			if (ch == '.') {
				dot = 1;
			} else if (dot == 0) {
				ret = (ret << 3) + (ret << 1) + ch - 48;
			} else {
				aft = (aft << 3) + (aft << 1) + ch - '0';
				num ++;
			}
			ch = getchar();
		}
		return (pow(0.1,num) * aft + ret) * w;
	}
	inline void write(int x) {
		if(x < 0) {
			putchar('-');
			x = -x;
		}
		if(x > 9) write(x / 10);
		putchar(x % 10 + '0');
	}
}
using namespace Newstd;
using PII = std::pair<int,int>;

const int INF = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 5;
struct Graph {
	int v,w,nxt;
} gra[N << 1];
int head[N],dis_s[N],dis_t[N],L[N],R[N],pre[N],ind[N];//ind:最短路上每条边的编号 
bool vis[N],path[N];
int n,m,q,len,idx = 1;
inline void add(int u,int v,int w) {
	gra[++ idx].v = v,gra[idx].w = w,gra[idx].nxt = head[u],head[u] = idx;
}
inline void dijkstra(int dis[],int st,int type = 0) {
	mst(vis,false);
	for (register int i = 1;i <= n; ++ i) dis[i] = INF;
	dis[st] = 0;
	std::priority_queue<PII,std::vector<PII>,std::greater<PII> >q;
	q.push(std::make_pair(dis[st],st));
	while (!q.empty()) {
		int u = q.top().second;q.pop();
		if (vis[u]) continue;
		vis[u] = true;
		for (register int i = head[u];i;i = gra[i].nxt) {
			int v = gra[i].v,w = gra[i].w;
//			debug(v,',');debug(w,'\n');
//			debug(dis[v],',');debug(dis[u] + w,'\n');
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w,pre[v] = i;
				q.push(std::make_pair(dis[v],v));
				if (type == 1 && path[v] == false) L[v] = L[u];
				else if (type == 2 && path[v] == false) R[v] = R[u];
			}
		}
	}
}
struct Segment_Tree {
	struct Node {
		int l,r;
		int Min;
	} node[N << 2];
	#define lson (p << 1)
	#define rson (p << 1 | 1)
	inline void pushup(int p) {
		node[p].Min = std::min(node[lson].Min,node[rson].Min);
	}
	inline void build(int p,int l,int r) {
		node[p].l = l,node[p].r = r,node[p].Min = INF;
		if (l == r) {
			return;
		}
		int mid = l + r >> 1;
		build(lson,l,mid),build(rson,mid + 1,r);
		pushup(p);
	}
	inline void update(int x,int y,int p,int k) {
		if (x <= node[p].l && node[p].r <= y) {
			node[p].Min = std::min(node[p].Min,k);
			return;
		}
		int mid = node[p].l + node[p].r >> 1;
		if (x <= mid) update(x,y,lson,k);
		if (y > mid) update(x,y,rson,k);
		// pushup(p); 
	}
	inline int query(int x,int y,int p) {
		if (x <= node[p].l && node[p].r <= y) {
			return node[p].Min;
		}
		int mid = node[p].l + node[p].r >> 1,res = node[p].Min;
		if (x <= mid) res = std::min(res,query(x,y,lson));
		if (y > mid) res = std::min(res,query(x,y,rson));
		return res;
	}
	#undef lson
	#undef rson 
} seg; 
signed main(void) {
	n = read(),m = read(),q = read();
	for (register int i = 1;i <= m; ++ i) {
		int u = read(),v = read(),w = read();
		add(u,v,w),add(v,u,w);
	}
	dijkstra(dis_t,n);
	L[1] = R[1] = 0,path[1] = true;
	int ver = 1;
	for (register int i = 1;ver != n; ++ i) {
		int id = pre[ver];
		ind[id / 2] = i;
		len ++;
		ver = gra[id].v ^ gra[id ^ 1].v ^ ver;
		path[ver] = true,L[ver] = R[ver] = i;
	}
	dijkstra(dis_s,1,1),dijkstra(dis_t,n,2);
	seg.build(1,1,len);
	for (register int i = 1;i <= m; ++ i) {
		if (!ind[i]) {
			int u = gra[i * 2].v,v = gra[i * 2 + 1].v,w = gra[i * 2].w;
			if (L[u] + 1 <= R[v]) seg.update(L[u] + 1,R[v],1,dis_s[u] + dis_t[v] + w);
			if (L[v] + 1 <= R[u]) seg.update(L[v] + 1,R[u],1,dis_s[v] + dis_t[u] + w);
		}
	}
	while (q --) {
		int t = read(),x = read();
		int u = gra[t * 2].v,v = gra[t * 2 + 1].v,w = gra[t * 2].w;
		// for (register int i = 1;i <= len; ++ i) printf("%lld,",seg.query(ind[i],ind[i],1));
		// puts("");
		if (!ind[t]) {
			if (x > w) {
				printf("%lld\n",dis_s[n]);
			} else if (x <= w) {
				printf("%lld\n",std::min(dis_s[n],std::min(dis_s[u] + dis_t[v] + x,dis_s[v] + dis_t[u] + x)));
			}
		} else {
			if (x > w) {
				printf("%lld\n",std::min(dis_s[n] - w + x,seg.query(ind[t],ind[t],1)));
			} else if (x <= w) {
				printf("%lld\n",dis_s[n] - w + x);
			}
		}
	}
	
	return 0;
}

标签:Taxi,std,Fee,dist,int,CF1163F,短路,include,dis
来源: https://www.cnblogs.com/Coros-Trusds/p/16336257.html