CF1715E Long Way Home
作者:互联网
套路题。
先不考虑额外的边跑一次最短路。
然后考虑一下额外的边,单独拿出来转移一次。
式子为 \(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;
}
标签:node,int,tp,long,qy,CF1715E,Way,Home,dis 来源: https://www.cnblogs.com/Qzong/p/16609260.html