题解:如何得到npy

题目链接

普及组模拟赛良心第四题,感觉比第三题简单捏。

这道题分成两问。对于前一问,简化题意是给定一棵有 \(n\) 个点的树,给定两个起点 \(s\)\(t\),求一个两个起点的“单”源最短路径。板子题咯,初始的优先队列把两个点都放进去就好了。

对于第二问,我们观察样例就可以发现,不管怎么构造,都只会有一个 \(0\)。手玩一下这个 \(0\) 的位置,容易得到实际上整棵树上的点被分为了两部分,一部分是最短路的起点为 \(s\),另一部分是最短路的起点为 \(t\),而那个 \(0\) 则恰好是两大部分交界的位置。

因此有一种构造方法,就是在跑最短路的时候记录下每一个点是由谁扩展来的,然后最后遍历一下每一条边判断方向即可。

\(Code\)

#include<bits/stdc++.h>
#define int long long
#define MAX 300010
using namespace std;

inline int read()
{
	int s=0,w=1;
	char c=getchar();
	while(!isdigit(c)) {if(c=='-') w=-1; c=getchar();}
	while(isdigit(c)) s=(s<<1)+(s<<3)+(c^48),c=getchar();
	return s*w;
}

int n,s,t;
int x,y,z;
int ans,lis[MAX];

struct edge
{
	int nex,to,val;
	int id;
}e[MAX<<1];
int head[MAX<<1],cnt,from[MAX<<1];
inline void add(int x,int y,int z,int id)
{
	cnt++;
	e[cnt].nex=head[x];
	e[cnt].to=y;
	e[cnt].val=z;
	e[cnt].id=id;
	head[x]=cnt;
	return;
}
inline bool cmp(edge a,edge b)
{
	return a.id<b.id;
}

int dis[MAX],vis[MAX];
priority_queue<pair<int,int> > q;
inline void dijkstra()
{
	memset(dis,0x3f,sizeof dis);
	memset(vis,0,sizeof vis);
	dis[s]=0,dis[t]=0;
	q.push(make_pair(0,s)),q.push(make_pair(0,t));
	while(!q.empty())
	{
		int t=q.top().second; q.pop();
		if(vis[t]) continue;
		vis[t]=1;
		for(int i=head[t];i;i=e[i].nex)
		{
			int to=e[i].to,val=e[i].val;
			if(dis[to]>dis[t]+val)
			{
				dis[to]=dis[t]+val;
				from[to]=t;
				q.push(make_pair(-dis[to],to));
			}
		}
	}
	return;
}

signed main()
{
	n=read(),s=read(),t=read();
	for(int i=1;i<n;++i)
		x=read(),y=read(),z=read(),add(x,y,z,i),add(y,x,z,i+n);
	dijkstra();
	for(int i=1;i<=n;++i)
		ans+=dis[i];
	cout<<ans<<endl;
	for(int i=1;i<=n;i++)
	{
		for(int j=head[i];j;j=e[j].nex)
		{
			int to=e[j].to,id=e[j].id;
			if(e[j].id>n) continue;
			if(from[to]==i)
				lis[id]=2;
			if(from[i]==to)
				lis[id]=1;
		}
	}
	for(int i=1;i<n;i++)
		cout<<lis[i];
	return (0-0);
}
posted @ 2022-09-04 23:35  LgxTpre  阅读(161)  评论(0编辑  收藏  举报