題目大意
一棵樹,求出隨機斷一條邊後,兩個聯通塊直徑和的最大值。
n<=100000,邊長<=100000
時間限制 1s
空間限制 256M
解題思路
對於樹上每一個點,預處理出以下數據:
1、每棵子樹的根節點到葉節點的最大值、次大值和第三大值d1,d2,d3;
2、每棵子樹內直徑長度f;
3、每棵子樹的子結點中f[son]的最大值和次大值;
4、這個點與該子樹以外的點的距離dist的最大值;
預處理之後,枚舉切斷哪條邊,然後O(1)得出直徑和即可。
#include<cstdio>
#include<cstring>
#include<algorithm>
#define maxn 200006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
struct poi
{
int x,y;
poi *nex;
} *a[maxn];
int i,n,x,y,z,fa[maxn];
ll ans,f[maxn],d1[maxn],d2[maxn],d3[maxn],jl[maxn];
ll jl2[maxn],s1[maxn],s2[maxn],di[maxn],anc[maxn];
void link(int x,int y,int z)
{
poi *p=new poi;
p->x=y;
p->y=z;
p->nex=a[x];
a[x]=p;
return;
}
void dfs(int x)
{
poi *p=new poi;
for(p=a[x];p;p=p->nex)
if (p->x!=fa[x])
{
int u=p->x;
fa[u]=x;
dfs(u);
if (d1[u]+p->y>d1[x])
{
d3[x]=d2[x];
d2[x]=d1[x];
jl2[x]=jl[x];
d1[x]=d1[u]+p->y;
jl[x]=u;
} else if (d1[u]+p->y>d2[x])
{
d3[x]=d2[x];
d2[x]=d1[u]+p->y;
jl2[x]=u;
} else if (d1[u]+p->y>d3[x])
d3[x]=d1[u]+p->y;
if (f[u]>s1[x])
{
s2[x]=s1[x];
s1[x]=f[u];
di[x]=u;
} else if (f[u]>s2[x])
s2[x]=f[u];
f[x]=max(f[x],f[u]);
}
f[x]=max(f[x],d1[x]+d2[x]);
return;
}
void redfs(int x)
{
poi *p=new poi;
for(p=a[x];p;p=p->nex)
if (p->x!=fa[x])
{
int u=p->x;
ll t1,t2;
t1=f[u];
if (u==jl[x]) t2=anc[x]+d2[x];
else t2=anc[x]+d1[x];
if (u==di[x]) t2=max(t2,s2[x]);
else t2=max(t2,s1[x]);
if (u==jl[x]) t2=max(t2,d2[x]+d3[x]);
else if (u==jl2[x]) t2=max(t2,d1[x]+d3[x]);
else t2=max(t2,d1[x]+d2[x]);
ans=max(ans,t1+t2);
redfs(u);
}
return;
}
void dfss(int x)
{
poi *p=new poi;
for(p=a[x];p;p=p->nex)
if (p->x!=fa[x])
{
int u=p->x;
anc[u]=anc[x]+p->y;
if (u==jl[x]) anc[u]=max(anc[u],d2[x]+p->y);
else anc[u]=max(anc[u],d1[x]+p->y);
dfss(u);
}
return;
}
int main()
{
scanf("%d",&n);
fr(i,1,n-1)
{
scanf("%d%d%d",&x,&y,&z);
link(x,y,z),link(y,x,z);
}
dfs(1);
dfss(1);
redfs(1);
printf("%lld\n",ans);
return 0;
}