ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces 1715E - Long Way Home

2022-08-21 14:30:40  阅读:177  来源: 互联网

标签:ch dist int ll Codeforces Long dijkstra Way qu


又是废掉的一个div2啊

第一次在学校熬夜打cf,开心还看到了自己最喜欢的斜率优化ohhh

链接 :E - Long Way Home

看到那个平方就可以靠感觉认为是斜率优化了....

感觉似不似有点想法??k只有20...

可以试着去考虑最后一步用飞机,然后跑dijkstra求出走普通路径的。

其实就这样了...


考虑k=1的情况:

在最后坐飞机,前面都普通路径行走

则:\(d_{new}[i]=min(d_{old}[j]+(i-j)^2)\)

\(d_{new}\)为最后的答案,就是在最后坐飞机,\(d_{old}\)就是前面已经处理的走普通路径

然后跑一遍dijkstra,看看是否会更新(即假设存在A->C的最短路径为:A->B最后坐飞机,B->C走普通路径)


处理k>1的情况也是一样的,做k次dp,每一次在dp后跑最短路看能否用普通路径更新。

注意的是在一开始要跑一遍最短路,代表坐0次飞机的最短路径。

然后就是对于这个dp式子的处理了:

观察发现可以把式子转换为:\(d_{old}[j]+j^2=2ij+d_{new}[i]-i^2\)

斜率为\(2i\),X为\(j\),Y为\(d_{old}[j]+j^2\)。斜率和X都单调递增,所以可以画图发现决策点是下凸(为什么不转换式子要画图?因为j有特殊的点)

这个j特殊的点就在于没有范围的限制,也就是范围是(1<=j<=n)

所以就不可以在循环中加入单调队列

可以先一遍循环把所有决策点存入单调队列,然后再一遍循环更新答案

就完了....

对了!还有一个点:因为m可能小于n,图可能不连通,也就是说从只1号点跑dijkstra就不一定可以遍历完,所以就需要在dp时如果更新了\(d_{new}\)就要把它放入优先队列中,以保证每个点都可以更新到。

Over.

一定要在计算Y的时候把\(j^2\)开成long long啊!!!麻了,改了一个小时(ku)

总的复杂度\(O(k(mlogn+n))\)

代码:

#include<bits/stdc++.h>
#define ll long long 
using namespace std;
inline int read(){
    register int x = 0, t = 1;
    register char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-')
            t=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        x=(x<<1)+(x<<3)+(ch^48);
        ch=getchar();
    }
    return x*t;
}
struct node{
	int to,nxt,w;
}e[200010];
int head[100010],cnt,vis[100010];
void add(int u,int v,int w){
	e[++cnt].to=v;
	e[cnt].nxt=head[u];
	e[cnt].w=w;
	head[u]=cnt;
}
ll dist[100010],dis[110000]/*old*/;
struct h{
	int id;
	ll dis;
	bool operator<(const h &other)const{
		return dis>other.dis;
	}
};
priority_queue<h>qu;
void dijkstra(){//更新以普通边结尾 
	memset(vis,0,sizeof(vis));
	qu.push((h){1,0});
	while(!qu.empty()){
		int p=qu.top().id;
		qu.pop();
		if(vis[p])continue;
		vis[p]=1;
		for(int i=head[p];i;i=e[i].nxt){
			int v=e[i].to;
			if(dist[v]>dist[p]+e[i].w){
				dist[v]=dist[p]+e[i].w;
				qu.push((h){v,dist[v]});
			}
		}
	}
}
int q[100010],hd,tl;
ll Y(int i){return dis[i]+(ll)i*i;/*爆了!!*/}
ll X(int i){return i;}
ll K(int i){return 2*i;}
double slope(int x,int y){//x>y
	if(X(x)==X(y)){
		if(Y(x)<Y(y))return -1e18;
		else return 1e18;
	}
	return (double)(Y(x)-Y(y))/(X(x)-X(y));
}
int main(){
	int n=read(),m=read(),k=read();
	for(int i=1;i<=m;i++){
		int x=read(),y=read(),w=read();
		add(x,y,w),add(y,x,w);
	}
	for(int i=2;i<=n;i++)dist[i]=1e18;
	dijkstra();
	while(k--){
		for(int i=1;i<=n;i++)dis[i]=dist[i];
		hd=tl=0;
		for(int i=1;i<=n;i++){
			//下凸壳
			while(hd+1<tl&&slope(i,q[tl-1])<=slope(q[tl-1],q[tl-2]))tl--;
			q[tl++]=i;
		}
		for(int i=1;i<=n;i++){
			while(hd+1<tl&&slope(q[hd+1],q[hd])<=K(i))hd++;
			if(hd<tl){
				int j=q[hd];
				if(dist[i]>dis[j]+(ll)(j-i)*(j-i)){
					dist[i]=dis[j]+(ll)(j-i)*(j-i);
					qu.push((h){i,dist[i]});
				}
			}
		}
		dijkstra();
	}
	for(int i=1;i<=n;i++)printf("%lld ",dist[i]);
	return 0;
}

标签:ch,dist,int,ll,Codeforces,Long,dijkstra,Way,qu
来源: https://www.cnblogs.com/lefy959/p/16609952.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有