题目大意
给你一颗n个点,边带权c[]的树,请构造一个排列p,求
∑i=1..ndis(pi,pi+1)
∑
i
=
1..
n
d
i
s
(
p
i
,
p
i
+
1
)
的最大值。
n≤1e5
解题思路
并不能使用暴力加优化。那么进一步观察性质。
考虑一条边i=(u,v)经过的上界,设s[i]=min(size[v[i]],size[u[i]]),即两边较小的连通分量大小。那么经过次数上界为2*s[i],这条边贡献2*s[i]*c[i]。猜一下结论:是否每条边都能达到次数上界呢?
随便拉一条边i出来,我们间隔地安排两边的点,这条边达到了上界,但很明显,如果两边大小不一样,大的一边的一些点会连在一起,那么大的分量内部不能都达到上界。
如果两边大小一样,我们发现,除了i会少一次,其他边都达到了上界,如果dis(p[n],p[1])也算,那就齐了。所以往重心方向思考。
那么上面说的两个重心的情况,答案就是
∑2∗si∗ci−c重心
∑
2
∗
s
i
∗
c
i
−
c
重
心
。如果是只有一个重心,很显然还是得随便找一条边让他次数-1,才能构造出合法的排列,那么找最小的边即可。
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
#define fo(i,j,k) for(i=j;i<=k;i++)
#define fd(i,j,k) for(i=j;i>=k;i--)
#define cmax(a,b) (a=(a>b)?a:b)
#define cmin(a,b) (a=(a<b)?a:b)
typedef long long ll;
const int N=1e6+5,M=2e6+5,mo=998244353;
int n,x,y,z,i,f[N],siz[N],len[N],mn,ce[5],p;
ll ans;
int tt,fst[N],nxt[N],b[N],c[N];
void cr(int x,int y,int z)
{
tt++;
b[tt]=y;
c[tt]=z;
nxt[tt]=fst[x];
fst[x]=tt;
}
void dfs(int x,int y)
{
siz[x]=1;
for(int p=fst[x];p;p=nxt[p])
if (b[p]!=y)
{
len[b[p]]=c[p];
dfs(b[p],x);
siz[x]+=siz[b[p]];
cmax(f[x],siz[b[p]]);
}
}
int main()
{
freopen("t2.in","r",stdin);
//freopen("t2.out","w",stdout);
scanf("%d\n",&n);
fo(i,1,n-1)
{
scanf("%d %d %d",&x,&y,&z);
cr(x,y,z);
cr(y,x,z);
}
dfs(1,0);
fo(i,1,n)
{
ans+=1ll*min(siz[i],siz[1]-siz[i])*len[i];
cmax(f[i],siz[1]-siz[i]);
}
ans*=2ll;
fo(i,1,n)
if ((!ce[1])||(f[i]<f[ce[1]]))
{
ce[0]=1;ce[1]=i;
}else if (f[i]==f[ce[1]])
{
ce[0]++;ce[2]=i;
}
if (ce[0]==2)
{
for (p=fst[ce[1]];p;p=nxt[p])
if (b[p]==ce[2])
ans-=c[p];
}else
{
mn=1e9;
for(p=fst[ce[1]];p;p=nxt[p])
cmin(mn,c[p]);
ans-=mn;
}
printf("%lld\n",ans);
}