传送门
题解:
边从小到大加入即可,我们只需要动态维护树的直径和经过当前边的最长链。
显然动态树可做,不过为 O(nlog2n) O ( n log 2 n )
直径有优美的性质,如果合并两颗树 S,T S , T ,之前的直径分别为 (Sx,Sy),(Tx,Ty) ( S x , S y ) , ( T x , T y ) ,那么新的直径一定是 (Sx,Sy),(Sx,Tx),(Sx,Ty)(Sy,Tx),(Sy,Ty),(Tx,Ty) ( S x , S y ) , ( S x , T x ) , ( S x , T y ) ( S y , T x ) , ( S y , T y ) , ( T x , T y ) 中的一个。 反证法很好证明。
同时容易证明经过当前边的最长链在 (Sx,Tx),(Sx,Ty)(Sy,Tx),(Sy,Ty) ( S x , T x ) , ( S x , T y ) ( S y , T x ) , ( S y , T y ) 中产生。
树链剖分,时间复杂度 O(nlogn) O ( n log n ) 。
#include
using namespace std;
typedef long long LL;
typedef pair <int,int> pii;
const int RLEN=1<<18|1;
inline char nc() {
static char ibuf[RLEN],*ib,*ob;
(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
char ch=nc(); int i=0,f=1;
while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
return i*f;
}
inline void W(LL x) {
static int buf[50];
if(!x) {putchar('0'); return;}
if(x<0) {putchar('-'); x=-x;}
while(x) {buf[++buf[0]]=x%10; x/=10;}
while(buf[0]) putchar(buf[buf[0]--]+'0');
}
const int N=3e5+50;
int n;
vector edge[N];
int dep[N], fa[N], top[N], sze[N], son[N], anc[N];
LL dis[N],ans;
struct chain {
int x,y; LL dis;
friend inline bool operator <(const chain &a,const chain &b) {return a.disstruct E {
int x,y,a;
friend inline bool operator <(const E &a,const E &b) {return a.ainline void dfs(int x,int f) {
sze[x]=1; anc[x]=x;
for(auto v:edge[x]) {
if(v.first==f) continue;
fa[v.first]=x;
dep[v.first]=dep[x]+1;
dis[v.first]=dis[x]+v.second;
dfs(v.first,x);
sze[x]+=sze[v.first];
son[x] = (sze[son[x]] < sze[v.first]) ? v.first : son[x];
}
}
inline void dfs2(int x,int f) {
for(auto v:edge[x]) {
if(v.first==f) continue;
top[v.first]=(v.first == son[x]) ? top[x] : v.first;
dfs2(v.first,x);
}
}
inline int lca(int x,int y) {
while(top[x]!=top[y]) {
(dep[top[x]] > dep[top[y]]) ? (x=fa[top[x]]) : (y=fa[top[y]]);
} return (dep[x] < dep[y]) ? x : y;
}
inline chain Dis(int x,int y) {return (chain){x,y,dis[x]+dis[y]-2*dis[lca(x,y)]};}
inline int ga(int x) {return (anc[x]==x) ? x : (anc[x]=ga(anc[x]));}
int main() {
n=rd();
for(int i=1;iint x=rd(), y=rd(), a=rd();
edge[x].push_back(pii(y,a));
edge[y].push_back(pii(x,a));
e[i]=(E) {x,y,a};
}
dfs(1,0); top[1]=1; dfs2(1,0);
sort(e+1,e+n);
for(int i=1;i<=n;i++) tr[i]=(chain) {i,i,0};
for(int i=n-1;i>=1;i--) {
int x=e[i].x, y=e[i].y, a=e[i].a;
if(fa[x]==y) swap(x,y);
x=ga(x); anc[y]=x;
chain mx=max(Dis(tr[x].x,tr[y].x), Dis(tr[x].x,tr[y].y));
mx=max(mx, max(Dis(tr[x].y, tr[y].x), Dis(tr[x].y,tr[y].y)));
ans=max(ans,a*mx.dis);
tr[x]=max(tr[x], max(tr[y],mx));
}
cout<