首页 > 编程学习 > CF1715E Long Way Home

CF1715E Long Way Home

发布时间:2022/8/21 5:23:22

套路题。

先不考虑额外的边跑一次最短路。

然后考虑一下额外的边,单独拿出来转移一次。

式子为 \(dis_u=min\{olddis_v+(u-v)^2,1\leq v \leq n\}\)

简单的,把凸包建出来,二分最优点转移即可。

也就是做一次斜率优化 \(dp\)

然后继续跑最短路,最短路可以同时 \(n\) 个节点一起跑。

重复 \(k\) 次。

复杂度 \(O(k(nlogm+nlogn))\)

#include<cstdio>
#include<algorithm>
#include<cstring>
const int N=100010;
#define ll long long
struct node{
	int id;
	ll val;
	bool operator<(const node &A)const {
		return val>A.val;
	}
};
struct heap{
	node st[N<<1];
	int tp;
	void push(node x){
		st[++tp]=x,std::push_heap(st+1,st+tp+1);
	}
	void pop(){
		std::pop_heap(st+1,st+tp+1),tp--;
	}
	node top(){
		return st[1];
	}
}q;
struct edge{
	edge*net;int to,c;
}e[N<<1],*tot=e,*head[N];
int n,m,k;
ll dis[N];
int vis[N];
void dij(){
	memset(vis,0,sizeof vis);
	for(int i=1;i<=n;i++)q.push(node{i,dis[i]});
	while(q.tp){
		int u=q.top().id;q.pop();
		if(vis[u])continue;
		vis[u]=1;
		for(edge*i=head[u];i;i=i->net)if(dis[u]+i->c<dis[i->to]){
			dis[i->to]=dis[u]+i->c;
			q.push(node{i->to,dis[i->to]});
		}
	}
}
long long qx[N],qy[N];
int tp;
int main(){
	scanf("%d%d%d",&n,&m,&k);
	for(int i=1,u,v,w;i<=m;i++)scanf("%d%d%d",&u,&v,&w),*++tot={head[u],v,w},head[u]=tot,*++tot={head[v],u,w},head[v]=tot;
	memset(dis,63,sizeof dis),dis[1]=0;
	dij();
	for(int i=1;i<=k;i++){
		tp=0;
		for(int j=1;j<=n;j++){
			long long ox=2*j,oy=dis[j]+1ll*j*j;
			while(tp>1&&(__int128)(oy-qy[tp])*(qx[tp]-qx[tp-1])<=(__int128)(qy[tp]-qy[tp-1])*(ox-qx[tp]))tp--;
			qx[++tp]=ox,qy[tp]=oy;
		}
		for(int j=1;j<=n;j++){
			int l=1,r=tp;
			while(l<r){
				int mid=l+r>>1;
				if(qy[mid+1]-qy[mid]<1ll*j*(qx[mid+1]-qx[mid]))l=mid+1;
				else r=mid;
			}
			dis[j]=1ll*j*j+qy[l]-1ll*j*qx[l];
		}
		dij();
	}
	for(int i=1;i<=n;i++)printf("%lld ",dis[i]);
	return 0;
}
Copyright © 2010-2022 mfbz.cn 版权所有 |关于我们| 联系方式|豫ICP备15888888号