2725: [Violet 6]故乡的梦

2725: [Violet 6]故乡的梦

Time Limit: 20 Sec   Memory Limit: 128 MB
Submit: 607   Solved: 190
[ Submit][ Status][ Discuss]

Description

Input

Output

Sample Input

6 7
1 2 1
2 3 1
3 4 2
4 5 1
5 6 1
1 3 3
4 6 3
1 6
4
1 2
1 3
4 3
6 5

Sample Output

7
6
Infinity
7

HINT

Source

[ Submit][ Status][ Discuss]



先做一遍Dijkstra求出最短路,这样的路径可能很多,任取一条

删边操作如果不涉及所选择的路径,那么不会影响答案

以s为起点,再做一遍Dijkstra,求出最短路图,对于每个点,预处理

ds[i]:从s到i出发最短路长度,fs[i]:到达i的路径上,最早能在点fs[i]离开所选择的最短路

同理,以t为起点,求出dt[i]与ft[i],含义类似

这样,就能表示出所有强制经过一条边(x,y)的最优路径,即

s -> fs[x] -> x -> y -> ft[y] -> t

处理时,让fs[i]在所选最短路中尽量靠前,ft[i]在所选最短路中尽量靠后

这样,只要是删除所选路径里[fs[x],ft[y]]之间的边,总是能用路径s -> fs[x] -> x -> y -> ft[y] -> t代替

换句话说,如果不存在这样的替代品,就没办法找到s -> t最短路了

区间修改线段树完成,注意我们并不需要真的构建出最短路图,Dijkstra过程中就可以递推了


要处理的数组很多,注意下标。。一开始写炸了。。GG

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 2E5 + 20;
const int T = 4;
typedef long long LL;
const LL INF = 1E16;

struct E{
	int to; LL w; E(){}
	E(int to,LL w): to(to),w(w){}
};

struct data{
	int num; LL d; data(){}
	data(int num,LL d): num(num),d(d){}
	bool operator < (const data & b) const {return d > b.d;}
};

int n,m,q,s,t,tot,fs[maxn],ft[maxn],Num[maxn],Fa[maxn];
LL Ans,dis[maxn],ds[maxn],dt[maxn],ans[maxn],c[maxn*T];
bool vis[maxn],bo[maxn];

vector <E> v[maxn];
queue <int> Q;
priority_queue <data> Q2;
stack <int> stk;

void Dijskra()
{
	for (int i = 1; i <= n; i++) dis[i] = INF,vis[i] = 0;
	dis[s] = 0; Q2.push(data(s,0));
	while (!Q2.empty())
	{
		data K = Q2.top(); Q2.pop(); 
		int k = K.num; if (vis[k]) continue; vis[k] = 1;
		for (int i = 0; i < v[k].size(); i++)
		{
			E e = v[k][i];
			if (dis[e.to] > dis[k] + e.w)
			{
				dis[e.to] = dis[k] + e.w; Fa[e.to] = k;
				if (!vis[e.to]) Q2.push(data(e.to,dis[e.to]));
			}
		}
	}
	Ans = dis[t]; if (Ans == INF) {while (q--) puts("Infinity"); exit(0);}
	for (int z = t; z != s; z = Fa[z]) stk.push(z); stk.push(s);
	while (!stk.empty()) 
	{
		int tp = stk.top(); stk.pop();
		Num[tp] = ++tot; bo[tp] = 1;
	}
}

void Dijskra2(int g,LL *Dis,int *fa)
{
	for (int i = 1; i <= n; i++) Dis[i] = INF,vis[i] = 0;
	Dis[g] = 0; Q2.push(data(g,0));
	while (!Q2.empty())
	{
		data K = Q2.top(); Q2.pop(); 
		int k = K.num; if (vis[k]) continue; 
		if (bo[k]) fa[k] = k; vis[k] = 1;
		for (int i = 0; i < v[k].size(); i++)
		{
			E e = v[k][i];
			if (Dis[e.to] > Dis[k] + e.w)
			{
				Dis[e.to] = Dis[k] + e.w; fa[e.to] = fa[k];
				Q2.push(data(e.to,Dis[e.to]));
			}
			else if (Dis[e.to] == Dis[k] + e.w)
			{
				if (s == g && Num[fa[k]] < Num[fa[e.to]]) fa[e.to] = fa[k];
				else if (t == g && Num[fa[e.to]] < Num[fa[k]]) fa[e.to] = fa[k];
			}
		}
	}
}

void Modify(int o,int l,int r,int ml,int mr,LL g)
{
	if (ml <= l && r <= mr) {c[o] = min(c[o],g); return;}
	int mid = (l + r) >> 1;
	if (ml <= mid) Modify(o<<1,l,mid,ml,mr,g);
	if (mr > mid) Modify(o<<1|1,mid+1,r,ml,mr,g);
}

void push_all(int o,int l,int r)
{
	if (l == r) {ans[l] = c[o]; return;}
	int mid = (l + r) >> 1;
	c[o<<1] = min(c[o<<1],c[o]);
	c[o<<1|1] = min(c[o<<1|1],c[o]);
	push_all(o<<1,l,mid); push_all(o<<1|1,mid+1,r);
}

int getint()
{
	char ch = getchar(); int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
		freopen("test.txt","w",stdout);
	#else
		freopen("2725.in","r",stdin);
		freopen("2725.out","w",stdout);
	#endif
	
	n = getint(); m = getint();
	while (m--)
	{
		int x = getint(),y,w;
		y = getint(); w = getint();
		if (x == y) continue;
		v[x].push_back(E(y,w));
		v[y].push_back(E(x,w));
	}
	s = getint(); t = getint(); q = getint();
	if (s == t) {while (q--) puts("0"); return 0;}
	Dijskra(); Dijskra2(s,ds,fs); Dijskra2(t,dt,ft);
	
	for (int i = 1; i < n*T; i++) c[i] = INF;
	for (int i = 1; i <= n; i++)
		for (int j = 0; j < v[i].size(); j++)
		{
			E e = v[i][j];
			int x = fs[i],y = ft[e.to];
			if (!x || !y || Num[x] > Num[y] || Num[y] - Num[x] <= 1) continue;
			Modify(1,1,tot,Num[x],Num[y] - 1,ds[i] + e.w + dt[e.to]);
		}
	push_all(1,1,tot);
	
	while (q--)
	{
		int x = getint(),y = getint();
		if (!bo[x] || !bo[y]) printf("%lld\n",Ans);
		else 
		{
			if (Num[x] > Num[y]) swap(x,y);
			if (Num[y] - Num[x] > 1) printf("%lld\n",Ans);
			else if (ans[Num[x]] == INF) puts("Infinity");
			else printf("%lld\n",ans[Num[x]]);
		}
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值