1 条题解

  • 0
    @ 2025-8-24 23:06:24

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar FL
    穷则独善其身,达则兼济天下 || 高天之歌,与风同唱;听凭风引,且听风吟;千风涤荡,温门永存!

    搬运于2025-08-24 23:06:24,当前版本为作者最后更新于2025-08-03 20:04:43,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    Solution

    先考虑子任务 33 怎么做。首先路径 121\to 2 必选,只需要考虑剩下的关键点中选择哪两个。

    对剩下的关键点跑多源最短路。由超级源点对关键点连边权为 00 的边,跑 dijkstra。于是我们就能得到每个点 uu 离最近关键点的距离 disudis_u,也能得到每个点的最近关键点 bub_u,或者说,这个图被分成若干个块,每个块对应一个关键点,块内的点都距离这个关键点最近。

    考虑最近的两个关键点之间的路径一定经过两个块的交界处,所以枚举边 ii,满足 buibvib_{u_i} \ne b_{v_i},求 disui+disvidis_{u_i}+dis_{v_i} 的最小值。

    考虑两对点怎么做。易证答案中的四个点中,必然有两个是距离最近的(或者你可以理解为就是子任务 33 求得的点),所以我们有两种思路,一种是两个距离最近的关键点连一条边,剩下两个距离次近的再连一条边,这可以仿照子任务 33 求出;另一种是两个距离最近的关键点分别找一个关键点连边,找到两个关键点距离最近的两个点,简单枚举即可。

    时间复杂度在 Dijkstra 和排序,为 O(nlogn)O(n\log n)

    Code

    #include <bits/stdc++.h>
    #define PII pair<int,int>
    using namespace std;
    const int N = 2e5+5,S = 2e5+4;
    int n,m,k,a[N],dis[5][N],pre[N],u[3000005],v[3000005],w[3000005],x,y,mmin=999999999,book[N];
    bool vis[5][N];
    struct node
    {
    	int v,w;
    };
    vector<node>vec[N];
    priority_queue<PII,vector<PII>,greater<PII>>q;
    PII o[N],p[N];
    void dijkstra(int u,int k)
    {
    	memset(dis[k],0x3f,sizeof dis[k]);
    	q.push({0,u});
    	dis[k][u] = 0;
    	while (!q.empty())
    	{
    		PII now = q.top();
    		q.pop();
    		if (vis[k][now.second]) continue;
    		vis[k][now.second] = 1;
    		for (node i: vec[now.second])
    		{
    			if (dis[k][i.v] > dis[k][now.second]+i.w)
    			{
    				dis[k][i.v] = dis[k][now.second]+i.w;
    				
    				if (now.second == S) pre[i.v] = i.v;
    				else pre[i.v] = pre[now.second];
    				q.push({dis[k][i.v],i.v});
    			}
    		}
    	}
    }
    signed main()
    {
    	ios_base::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    	cin >> n >> m >> k;
    	for (int i = 1; i <= m; i++)
    	{
    		cin >> u[i] >> v[i] >> w[i];
    		vec[u[i]].push_back({v[i],w[i]});
    		vec[v[i]].push_back({u[i],w[i]});
    	}
    	for (int i = 1; i <= k; i++)
    	{
    		cin >> a[i];
    		book[a[i]] = 1;
    		vec[S].push_back({a[i],0});
    	}
    	dijkstra(S,0);
    	for (int i = 1; i <= m; i++)
    		if (pre[u[i]] != pre[v[i]] && dis[0][u[i]]+dis[0][v[i]]+w[i] < mmin)
    			mmin = dis[0][u[i]]+dis[0][v[i]]+w[i],x = pre[u[i]],y = pre[v[i]];
    //	cout << x << ' ' << y << ' ' << mmin << '\n';
    	dijkstra(x,1);
    	dijkstra(y,2);
    	int ans = 999999999;
    	int cnt1 = 0,cnt2 = 0;
    	for (int i = 1; i <= n; i++)
    		if (book[i]) o[++cnt1] = {dis[1][i],i};
    	sort(o+1,o+cnt1+1);
    	for (int i = 1; i <= n; i++)
    		if (book[i]) p[++cnt2] = {dis[2][i],i};
    	sort(p+1,p+cnt2+1);
    	if (cnt1 >= 4)
    	{
    		if (o[3].second == p[3].second) ans = min(o[3].first+p[4].first,o[4].first+p[3].first);
    		else ans = o[3].first+p[3].first;
    	}
    	for (int i = 0; i < vec[S].size(); i++)
    		if (vec[S][i].v == x || vec[S][i].v == y) vec[S][i].w = 999999999;
    	dijkstra(S,3);
    	int min1 = 999999999;
    	for (int i = 1; i <= m; i++)
    		if (pre[u[i]] != pre[v[i]] && dis[3][u[i]]+dis[3][v[i]]+w[i] < min1)
    			min1 = dis[3][u[i]]+dis[3][v[i]]+w[i];
    	cout << min(ans,mmin+min1);
    	return 0;
    }
    
    • 1

    信息

    ID
    10996
    时间
    6000ms
    内存
    1024MiB
    难度
    (无)
    标签
    递交数
    0
    已通过
    0
    上传者