【GJOI 2023.10.6 T2】 亿只只因的回家路
亿只只因的回家路
题意:给出一个 \(n\) 点 \(m\) 边的无向图,每条边有长度 \(v_i\) , 有 \(k\) 只小鸡,第 \(i\) 只小鸡在 \(id_i\) 号节点,鸡妈妈在 \(1\) 号点,现鸡妈妈要接所有的小鸡,小鸡与鸡妈妈的速度为 \(1\) ,问最短多久鸡妈妈才能接到所有的小鸡 ,\(n \le 10^5,k \le 2 \times 10^5\)。
由于他们的速度都是 \(1\) ,所以可以看到他们都会集中到一个汇合点。
转化成他们到一个点的最短时间是多少。
由于这个点可能在边上,所以我们需要分类讨论。
找出这堆鸡到每个点的最短距离,时间复杂度 \(O(knlogn)\) 。
枚举点很简单,如何处理点在边上的情况呢?
首先,每只鸡肯定都是从边的两端进一条边的。
由于只需考虑最晚时间,所以只用找从两端进最晚的哪只鸡。
不可以贪心选最小。
我们这样考虑:将每只小鸡按从左端进的时间排序,若最晚的是第 \(i\) 只小鸡,可见 \(i\) 前的都走 \(i\) 是最优选择。
那后面的都要走右边,找出枚举找最优解即可。
时间复杂度 \(O(knlogn + mklogk)\) 。
Code
#include<bits/stdc++.h>
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#define min(a,b) (a<b?a:b)
#define max(a,b) (a>b?a:b)
using namespace std;
struct datay
{
int x;
int y;
}b[25];
bool operator<(const datay &q,const datay &w)
{
return q.y>w.y;
}
priority_queue<datay> l;
int n,m,de[25],start;
int f[100005],dis[25][100005];
vector<int> a[100005];
vector<int> t[100005];
bool v[100005];
bool cmp1(datay q,datay w)
{
return q.x<w.x;
}
int h;
char c;
int read()
{
h=0;
c=getchar();
while((c<'0'||c>'9'))c=getchar();
while(c>='0'&&c<='9')h=h*10+c-'0',c=getchar();
return h;
}
void dij()
{
for(register int i=1;i<=n;++i)f[i]=1e9+5;
memset(v,false,sizeof(v));
f[start]=0;
datay q,w;
q.x=start;
q.y=0;
l.push(q);
while(l.size()!=0)
{
q=l.top();
l.pop();
if(v[q.x])continue;
v[q.x]=true;
for(int i=0;i<a[q.x].size();i++)
{
w.x=a[q.x][i];
w.y=q.y+t[q.x][i];
if(w.y<f[w.x])l.push(w);
f[w.x]=min(f[w.x],w.y);
}
}
return;
}
int main()
{
int x,y;
int z;
n=read();
m=read();
for(int i=1;i<=m;i++)
{
x=read();
y=read();
z=read();
a[x].push_back(y);
a[y].push_back(x);
t[x].push_back(z);
t[y].push_back(z);
}
m=read();
for(int i=1;i<=m;i++)
{
de[i]=read();
start=de[i];
dij();
for(int j=1;j<=n;j++)dis[i][j]=f[j];
}
m++;
de[m]=1;
start=de[m];
dij();
for(register int i=1;i<=n;i++)dis[m][i]=f[i];
int s=1e9+5,p=0,q,w,e;
for(register int i=1;i<=n;i++)
{
p=0;
for(int j=1;j<=m;j++)p=max(p,dis[j][i]);
s=min(s,p*2);
}
for(register int qwe=1;qwe<=n;qwe++)
{
for(int rty=0;rty<a[qwe].size();rty++)
{
x=qwe;
y=a[qwe][rty];
z=t[qwe][rty];
p=0;
for(int i=1;i<=m;i++)b[i].x=dis[i][x],b[i].y=dis[i][y];
sort(b+1,b+m+1,cmp1);
for(int i=m-1;i>=1;i--)
{
b[i].y=max(b[i].y,b[i+1].y);
}
for(int i=m-1;i>=1;i--)
{
q=b[i].x;
w=b[i+1].y;
e=abs(q-w);
s=min(s,(max(q,w)*2)+(z-e>0?z-e:0));
}
}
}
printf("%d",s);
return 0;
}