luogu P4408 [NOI2003]逃学的小孩

题面传送门
显然最长的一条是树的直径。
那么找到树的直径后另一条枚举点然后跑 s p f a spfa spfa即可。
代码实现:

#include
#include
#include
#define min(a,b) ((a)<(b)?(a):(b))
#define max(a,b) ((a)>(b)?(a):(b))
using namespace std;
int n,m,k,x,y,z,maxs,start,now,cur;
long long maxn,d[3][200039],ans,tot,pus;
struct yyy{
     int to,w,z;}tmp;
struct ljb{
     
	int head,h[200039];
	yyy f[400039];
	inline void add(int x,int y,int z){
     
		f[++head]=(yyy){
     y,z,h[x]};
		h[x]=head;
	}
}s;
inline void dfs(int x,int last,long long d){
     
	if(d>maxn){
     
		maxn=d;
		maxs=x;
	}
	int cur=s.h[x];
	yyy tmp;
	while(cur!=-1){
     
		tmp=s.f[cur];
		if(tmp.to!=last) dfs(tmp.to,x,d+tmp.w);
		cur=tmp.z;
	}
}
queue<int > q;
int main(){
     
	memset(s.h,-1,sizeof(s.h));
	memset(d[1],0x3f,sizeof(d[1]));
	memset(d[2],0x3f,sizeof(d[2]));
	register int i;
	scanf("%d%d",&n,&m);
	for(i=1;i<=m;i++) scanf("%d%d%d",&x,&y,&z),s.add(x,y,z),s.add(y,x,z);
	dfs(1,1,0);
	start=maxs;
	maxn=0;
	dfs(maxs,maxs,0);
	d[1][start]=0;
	q.push(start);
	while(!q.empty()){
     
		now=q.front();
		q.pop();
		cur=s.h[now];
		while(cur!=-1){
     
			tmp=s.f[cur];
			if(d[1][tmp.to]>d[1][now]+tmp.w) q.push(tmp.to),d[1][tmp.to]=d[1][now]+tmp.w;
			cur=tmp.z;
		}
	}
	d[2][maxs]=0;
	q.push(maxs);
	while(!q.empty()){
     
		now=q.front();
		q.pop();
		cur=s.h[now];
		while(cur!=-1){
     
			tmp=s.f[cur];
			if(d[2][tmp.to]>d[2][now]+tmp.w) q.push(tmp.to),d[2][tmp.to]=d[2][now]+tmp.w;
			cur=tmp.z;
		}
	}
	for(i=1;i<=n;i++)ans=max(ans,min(d[1][i],d[2][i])+maxn);
	printf("%lld\n",ans);
}

你可能感兴趣的:(洛谷,dfs,树的直径,spfa)