[CF702E]Paired Payment

壹、题目描述 ¶

传送门 to CF.

中文大意:

给定图 \(G=\lang V,E\rang\)(不一定保证 \(G\) 是一个连通图),请你找到从 \(1\) 开始到达任意一个点 \(t(t\in [1,n])\) 的最短路长度。

但是每次你不能只走 \(E\) 中的一条边,而是选择两条边 \(e_1,e_2\in E\;\text{s.t.}\;e_1=\lang x,u,w_1\rang,e_2=\lang u,y,w_2\rang\),然后,执行 \(x\overset{e_1}\rightarrow u\overset{e_2}\rightarrow y\) 且每次走的花费是 \((w_1+w_2)^2\).

保证 \(|V|\le 10^5,|E|\le \min\left\{2\times 10^5,{|V|\times (|V|-1)\over 2}\right\},\forall e=\lang u,v,w\rang \in E,1\le w\le 50\and u\neq v\).

贰、题解 ¶

§ Hint1 §

你真的看到 \(\forall e=\lang u,v,w\rang \in E,w\le 50\) 了吗?

§ Hint2 §

对于一个中间节点,它前一步走的边的权值会对下一步造成影响。

正是因为这个影响,让我们无法跑 \(\tt dijkstra\),那么如何处理这个影响才能让 \(\tt dijkstra\) 继续工作?

§ Hint3 §

边的权值最大只有 \(50\),我们是否可以记录走到一个节点时它前一步边的权值为多少,让不同情况分开计算,使得我们的 \(\tt dijkstra\) 能够继续工作?

§ 正解 §

由于我们是一次走两条边,对于 \(x\rightarrow u\rightarrow y\) 的中间节点 \(u\),我们实际上需要关心的是它前一步走的边的权值是多少,不难发现,对于一个点,它前一步边的权值最多只有 \(50\) 种,所以对于一个点 \(u\),我们可以记录它前一步走的边的权值 \(i(i\in [0,50])\),可以考虑开一个 \(\tt dis[u][i]\) 表示走到点 \(u\),前一步的边权值为 \(i\) 进行记录,但是为什么 \(i\) 可以取 \(0\)?这是为了算法的普遍性,\(i=0\) 表示的并不是点 \(u\) 是中间点,而是结束点,这样,我们可以通过询问 \(\tt dis[u][0]\) 是否为 \(+\infty\) 来判断是否存在路径从 \(1\)\(u\).

然后,直接在这个图上面跑 \(\tt dijkstra\) 就可以了,时间复杂度 \(\mathcal O(|E|\times \max W\times \log |E|)\),空间复杂度 \(\mathcal O(|V|\max W)\),其中 \(W\) 表示边权。

叁、参考代码 ¶

const int maxn=1e5;
const int maxm=2e5;
const ll inf=1ll<<60;

vector<pii>g[maxn+5];
int n, m;

inline void input(){
	n=readin(1), m=readin(1);
	int u, v, w;
	rep(i, 1, m){
		u=readin(1), v=readin(1), w=readin(1);
		g[u].push_back(mp(v, w));
		g[v].push_back(mp(u, w));
	}
}

struct node{
	int u, pre; ll d;
	node(){}
	node(int U, int P, ll D): u(U), pre(P), d(D){}
	inline int operator <(const node rhs) const{
		return d>rhs.d;
	}
};
priority_queue<node>Q;
ll dis[maxn+5][55];
inline void dijkstra(){
	rep(i, 1, n) rep(j, 0, 50) dis[i][j]=inf;
	Q.push(node(1, 0, 0));
	dis[1][0]=0;
	while(!Q.empty()){
		node cur=Q.top(); Q.pop();
		int u=cur.u, pre=cur.pre;
		if(dis[u][pre]<cur.d) continue;
		for(pii to: g[u]){
			int v=to.fi, nxt=pre? 0: to.se;
			if(dis[v][nxt]>dis[u][pre]+2*pre*to.se+to.se*to.se)
				Q.push(node(v, nxt, dis[v][nxt]=dis[u][pre]+2*pre*to.se+to.se*to.se));
		}
	}
}

signed main(){
	input();
	dijkstra();
	rep(i, 1, n) printf("%lld ", dis[i][0]==inf? -1: dis[i][0]);
	return 0;
}
posted @ 2021-05-13 17:47  Arextre  阅读(50)  评论(0编辑  收藏  举报