P2993 [FJOI2014]最短路径树问题

题目

P2993 [FJOI2014]最短路径树问题

给定一个无向图,求出其最短路径树上面的,包含 \(k\) 个点的一条路径,使得这条路径权值尽可能大,并求出有多少条长度为这个的路径(不要求为 \(k\) 个点)。

分析

没意思题,点分治+最短路。

先直接跑最短路后建出树来。

然后如果把点数当作边权,把路径权值当作价值,题目就相当于是P4149 [IOI2011]Race求最大值了。

然后求出最大值后,考虑统计答案,相当于就是统计树上距离为 \(D\) 的点对个数,模板。

代码

#include<bits/stdc++.h>
using namespace std;
template <typename T>
inline void read(T &x){
    x=0;char ch=getchar();bool f=false;
    while(!isdigit(ch)) f|=ch=='-',ch=getchar();
    while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
    x=f?-x:x;return;
}
template <typename T>
inline void write(T x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10^48);
	return;
}
const int N=2e5+5,INF=1e9+7;
int n,m,k;
int head[N],nex[N],to[N],w[N],idx;
int dis[N],vis[N],pre[N],val[N];
int t[N],Vis[N],t1[N],tot[N],tmp;
int Ans,Num,Root,Max,Size,siz[N],son[N];
inline void add(int x,int y,int z){idx++;nex[idx]=head[x];head[x]=idx;to[idx]=y;w[idx]=z;}
priority_queue<pair<int,int> >q;
inline void GetRoot(int x,int fa){
	siz[x]=1;son[x]=0;
	for(int i=head[x];i;i=nex[i]){
		int t=to[i];
		if(t==fa||vis[t])continue;
		GetRoot(t,x);siz[x]+=siz[t];
		if(son[x]<siz[t]) son[x]=siz[t];
	}
	if(son[x]<Size-siz[x]) son[x]=Size-siz[x];
	if(Max>son[x])Max=son[x],Root=x;
	return ;
}
inline void Calc(int x,int fa,int dist,int dep){
	if(t1[dep]<dist) t1[dep]=dist,tot[dep]=1;
	else if(t1[dep]==dist)	tot[dep]++;
	if(dep>tmp)tmp=dep;
	for(int i=head[x];i;i=nex[i]){
		int t=to[i];
		if(t==fa||vis[t])continue;
		Calc(t,x,dist+w[i],dep+1);
	}
	return ;
}
inline void DFS(int x){
	Vis[0]=vis[x]=true;
	int dep=0;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];tmp=0;
		if(vis[y])continue;
		Calc(y,x,w[i],1);
		if(tmp>dep) dep=tmp;
		for(int j=1;j<=tmp;j++){
			if(Vis[k-1-j]){
				if(Ans<t1[j]+t[k-1-j]) Ans=t1[j]+t[k-1-j],Num=tot[j]*Vis[k-1-j];
				else if(Ans==t1[j]+t[k-1-j]) Num+=tot[j]*Vis[k-1-j];
			}
		}
		for(int j=1;j<=tmp;j++){
			if(t1[j]>t[j]) t[j]=t1[j],Vis[j]=tot[j];
			else if(t1[j]==t[j]) Vis[j]+=tot[j];
		}
		for(int j=1;j<=tmp;j++) t1[j]=tot[j]=0;
	}
	for(int i=0;i<=dep;i++) t[i]=Vis[i]=0;
	for(int i=head[x];i;i=nex[i]){
		int y=to[i];
		if(vis[y])continue;
		Root=0,Max=INF,Size=siz[y];
		GetRoot(y,x);
		DFS(Root);
	}
	return ;
}
void Dijkstra(){
	memset(dis,0x3f,sizeof(dis));
	dis[1]=0;q.push(make_pair(0,1));
	while(!q.empty()){
		int x=q.top().second;q.pop();
		if(vis[x]) continue;
		vis[x]=true;
		for(int i=head[x];i;i=nex[i]){
			int t=to[i];
			if(dis[t]>dis[x]+w[i]){
				dis[t]=dis[x]+w[i],pre[t]=x,val[t]=w[i];
				q.push(make_pair(-dis[t],t));
			}
			else if(dis[t]==dis[x]+w[i]&&w[i]>val[t]) pre[t]=x,val[t]=w[i];
		}
	}
	idx=0;memset(head,0,sizeof(head));
	for(int i=2;i<=n;i++) add(i,pre[i],val[i]),add(pre[i],i,val[i]);
	return ;
}
int main(){
	read(n),read(m),read(k);
	for(int i=1;i<=m;i++){
		int x,y,z;
		read(x),read(y),read(z);
		add(x,y,z),add(y,x,z);
	}
	Dijkstra();
	Max=INF,Size=n,Root=0;
	memset(vis,0,sizeof(vis));
	GetRoot(1,0);
	DFS(Root);
	write(Ans),putchar(' '),write(Num);
	return 0;
}
posted @ 2021-05-02 23:59  __Anchor  阅读(90)  评论(0编辑  收藏  举报