树上最长路 sol
程序员文章站
2022-05-12 12:26:01
...
树上最长路
题目描述
给定一棵有个结点的树,树上每条边的长度为.
定义一棵树上的最长路为所有点对间,最短路最长的那对点间的最短路径长度。
在树中删去任意一条边,都会使得原树分为恰好两棵互相之间不连通的子树,现在君想知道删去每一条边后, 剩下的两棵子树中的最长路的较大值是多少。
为了方便起见,你只需要告诉 君删去每一条边后得到的最长路较大值的和。
输入格式
第一行一个整数,表示树的结点数
接下来行每行三个整数
表示一条连接的长度为的无向边
输出格式
仅一行一个整数表示答案
样例
input
5
2 1 7
3 1 7
4 2 5
5 2 6
output
63
数据范围
的数据:
的数据:
另外的数据:所有点度数均小于且最多只有一个点度数为
另有的数据:树为随机生成,第条边连接间随机一点与点
的数据: ,
sol:
对于前的数据,都可以枚举删除每条边,直接做
下面考虑正解:
首先对于一个不在直径上的边,删除它之后对答案的贡献不变
对于此图,若我们删除这条边,则这次删除操作对于答案的没有影响,还是直径
若对于直径上的边,则答案就是以被删除的边的两个点为根分别求出两个联通快的最长链和次长链
然后就没了。。
具体细节看代码注释
Code:
#include<bits/stdc++.h>
using namespace std;
#define f1(a,b,c) for(ll c=a;c<=b;c++)
#define f2(a,b,c) for(int c=a;c>=b;c--)
#define f3(a,b,c) for(int c=a;c;c=b)
#define so1(a,n) sort(a+1,a+n+1,mycmp);
#define so2(a,n) sort(a+1,a+n+1);
#define re(a,n) reverse(a+1,a+n+1);
#define ll long long
#define itn int
#define ubt int
#define mp make_pair
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define DEBUG puts("FUCK");
const int twx=1e5+100;
const int inf=0x3f3f3f3f;
ll read()
{
ll sum=0;
ll flag=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
{
flag=-1;
}
c=getchar();
}
while(c>='0'&&c<='9')
{
sum=((sum*10)+c-'0');
c=getchar();
}
return sum*flag;
}
vector<pll> G[twx];
ll n;
ll d[twx];
ll X[twx];
ll Y[twx];
ll on[twx];
ll s;
ll t;
ll MAX[twx][3][2];
ll Deep[twx][2];
ll ans=0;
void get_diameter(ll x,ll fa)//求直径
{
f1(0,(ll)G[x].size()-1,i)
{
ll y=G[x][i].first;
ll z=G[x][i].second;
if(y==fa)
{
continue ;
}
d[y]=d[x]+z;
get_diameter(y,x);
}
}
bool get_on_diameter(ll x,ll fa)//判断哪些点在直径上
{
if(x==t)
{
on[x]=1;
return 1;
}
f1(0,(int)G[x].size()-1,i)
{
ll y=G[x][i].first;
if(y==fa)
{
continue ;
}
on[x]|=get_on_diameter(y,x);
}
return on[x];
}
void get_endpoint()//求直径的两个端点
{
get_diameter(1,0);
f1(1,n,i)
{
if(d[i]>d[s])
{
s=i;
}
}
d[s]=0;
get_diameter(s,0);
f1(1,n,i)
{
if(d[i]>d[t])
{
t=i;
}
}
on[s]=1;
}
void get_second_path(ll op,ll x,ll fa)
{
Deep[x][op]=Deep[fa][op]+1;
f1(0,(ll)G[x].size()-1,i)
{
ll y=G[x][i].first;
ll z=G[x][i].second;
if(y==fa)
{
continue ;
}
get_second_path(op,y,x);
ll tmp=MAX[y][1][op]+z;
if(tmp>MAX[x][1][op])
{
MAX[x][2][op]=MAX[x][1][op];
MAX[x][1][op]=tmp;
}
else if(tmp>MAX[x][2][op])
{
MAX[x][2][op]=tmp;
}
MAX[x][0][op]=max(MAX[x][0][op],MAX[y][0][op]);
}
MAX[x][0][op]=max(MAX[x][0][op],MAX[x][1][op]+MAX[x][2][op]);
}
void init()
{
n=read();
f1(1,n-1,i)
{
ll x=read();
ll y=read();
ll z=read();
G[x].pb(mp(y,z));
G[y].pb(mp(x,z));
X[i]=x;
Y[i]=y;
}
}
void work()
{
get_on_diameter(s,0);
get_second_path(0,s,0);
get_second_path(1,t,0);
f1(1,n-1,i)
{
ll XX=X[i];
ll YY=Y[i];
if(!on[XX]||!on[YY])//不在直径上的边贡献直接加
{
ans+=d[t];
continue ;
}
if(Deep[XX][0]<Deep[YY][0])
{
ans+=max(MAX[XX][0][1],MAX[YY][0][0]);
}
else
{
ans+=max(MAX[XX][0][0],MAX[YY][0][1]);
}
}
}
void print()
{
printf("%lld\n",ans);
}
int main()
{
//freopen("tree.in","r",stdin);
//freopen("tree.out","w",stdout);
init();
get_endpoint();
work();
print();
return 0;
}