【正经题解】树网的核
2024-02-20 17:22:19
发布于:浙江
13阅读
0回复
0点赞
一个线性时间复杂度的做法
找一条直径(两遍dfs),然后从一个端点开始枚举长度不超过s的另一端点(由贪心的性质显然当长度刚好小于s时比较优 )
然后偏心距的下界大于这个端点到直径两端点的最小值
然后对于一条路径的偏心距我们发现如果去一个点要经过你的路径,这个距离显然是没有用的(因为从路径上到这个点一定有更小的距离)
所以我们就将他们无视掉
#include<bits/stdc++.h>
using namespace std;
#define maxn 500005
inline int read()
{
char ch='*';
int num=0,f=1;
while(!isdigit(ch)){
ch=getchar();
if(ch == '-' ) f = -1;
}
while(isdigit(ch))
{
num = num * 10 +ch -'0';
ch = getchar();
}
return num*f;
}
//struct edge {int to,val};
vector<pair<int ,int > > e[maxn];
int dis[maxn];
bool vis[maxn];
int fa[maxn];
int n,m,s;
void dfs(int x)
{
int siz=e[x].size();
siz--;
for(int i=0;i<=siz;i++)
{
int v=e[x][i].first;
if(vis[v]||fa[x]==v) continue ;
fa[v]=x;
dis[v]=dis[x]+e[x][i].second;
dfs(v);
}
return;
}
int main()
{
n=read();
s=read();
int u,v,w;
for(int i=1;i<n;i++)
{
u=read();v=read();w=read();
e[u].push_back(make_pair(v,w));
e[v].push_back(make_pair(u,w));
}
int l=1,l2=1;
dis[l]=0;
dfs(l);
memset(fa,0,sizeof(fa));
for(int i=1;i<=n;i++) if(dis[i]>dis[l]) l=i;
dis[l]=0; dfs(l);
for(int i=1;i<=n;i++) if(dis[i]>dis[l2] ) l2=i;
int ans=0x7fffffff,j=l2;
for(int i=l2;i;i=fa[i]){
while(fa[j]&&dis[i]-dis[fa[j]]<=s) j=fa[j];
ans=min(ans,max(dis[j],dis[l2]-dis[i]));
}
for(int i=l2;i;i=fa[i]) vis[i]=1;
for(int i=l2;i;i=fa[i]) dis[i]=0,dfs(i);
for(int i=1;i<=n;i++) ans=max(ans,dis[i]);
cout<<ans<<endl;
return 0;
}
这里空空如也
有帮助,赞一个