一棵树,求出随机断一条边后,两个联通块直径和的最大值。
n<=100000,边长<=100000
时间限制 1s
空间限制 256M
对于树上每一个点,预处理出以下数据:
1、每棵子树的根节点到叶节点的最大值、次大值和第三大值d1,d2,d3;
2、每棵子树内直径长度f;
3、每棵子树的子结点中f[son]的最大值和次大值;
4、这个点与该子树以外的点的距离dist的最大值;
预处理之后,枚举切断哪条边,然后O(1)得出直径和即可。
#include
#include
#include
#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;
}