题意
求一棵树/一个环套树的两点最短距离的最大值。
//和图的直径有所不同
解题思路
代码繁琐。思想简单。比赛时没拍。
求图的直径。
环套树,记dis(x,y)为环上的点x到点y的最短路径。
显然,给环定一个方向,求个前缀和。对于每个环上的点x,必有一个a[x],表示按照给定的方向走,第一个满足环长len-(sum[a[x]]-sum[x])<sum[a[x]]-sum[x]
a[x]显然不递减。
所以拿个线段树维护一下。一个区间加,一个区间减。
据说还可以单调队列,
O
(
n
)
O(n)
O(n)做。
代码
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#define N 1000005
#define LL long long
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
struct Note{
int x,y;
LL z;
}c[N];
struct note{
int to,next,val;
}edge[N<<1];
struct sgm{
LL la,mx;
}tr[N*12];
int Tot,head[N];
int i,j,k,l,n,m,gx,gy;
int opl,opr,L1,R1;
LL opz;
LL mx[N],cmx[N],E[N*3];
int dep[N];
int fa[N],o[N],o1[N];
int T,tot,cnt,opx;
int L2,R2;
int f[N],g[N];
int A,B;
LL ans,cd,C,D1,cd1;
bool bz[N];
int read(){
int rs=0,fh=1;char ch;
while((ch<'0'||ch>'9')&&(ch^'-'))ch=getchar();
if(ch=='-')fh=-1,ch=getchar();
while(ch>='0'&&ch<='9')rs=(rs<<3)+(rs<<1)+(ch^'0'),ch=getchar();
return rs;
}
int get(int x){return f[x]==x?x:f[x]=get(f[x]);}
void lb(int x,int y,int z){
edge[++Tot].to=y;
edge[Tot].next=head[x];
edge[Tot].val=z;
head[x]=Tot;
}
void dg(int x){
int i;
for(i=head[x];i;i=edge[i].next)
if(edge[i].to^fa[x]){
g[edge[i].to]=edge[i].val;
fa[edge[i].to]=x;
dep[edge[i].to]=dep[x]+1;
dg(edge[i].to);
}
}
void dg1(int x){
int i;
for(i=head[x];i;i=edge[i].next)
if((edge[i].to^fa[x])&&!bz[edge[i].to]){
fa[edge[i].to]=x;
dg1(edge[i].to);
C=mx[edge[i].to]+edge[i].val;
if(C>=mx[x])cmx[x]=mx[x],mx[x]=C;
else
if(C>=cmx[x])cmx[x]=C;
}
}
int getlca(int A,int B){
int i,A1=A,B1=B;
if(dep[A1]<dep[B1])swap(A1,B1);
while(dep[A1]>dep[B1])A1=fa[A1];
if(A1==B1)return A1;
while(A1^B1)A1=fa[A1],B1=fa[B1];
return A1;
}
void chuli(){
int i,A1=A,B1=B;
tot=dep[A]+dep[B]-2*dep[C]+1;
if(dep[A1]<dep[B1])swap(A1,B1);
while(dep[A1]>dep[B1]){
cnt++;
o[cnt]=A1;
o1[cnt+1]=g[A1];
A1=fa[A1];
}
if(A1==B1){
o[++cnt]=A1;
return;
}
int D=tot;
while(A1^B1){
cnt++;
o[cnt]=A1;
o1[cnt+1]=g[A1];
A1=fa[A1];
o[D]=B1;
o1[D]=g[B1];
B1=fa[B1];
D--;
}
o[D]=A1;
}
void update(int ps){
tr[ps].mx=max(tr[ps<<1].mx,tr[(ps<<1)|1].mx);
}
void downld(int ps){
if(tr[ps].la!=0){
tr[ps<<1].mx+=tr[ps].la;
tr[(ps<<1)|1].mx+=tr[ps].la;
tr[ps<<1].la+=tr[ps].la;
tr[(ps<<1)|1].la+=tr[ps].la;
tr[ps].la=0;
}
}
void change(int ps,int l,int r){
if(opl<=l&&r<=opr){
tr[ps].la+=opz;
tr[ps].mx+=opz;
return;
}
downld(ps);
int wz=(l+r)>>1;
if(opl<=wz)change(ps<<1,l,wz);
if(opr>wz)change((ps<<1)|1,wz+1,r);
update(ps);
}
LL query(int ps,int l,int r){
if(opl<=l&&r<=opr){
return tr[ps].mx;
}
downld(ps);
LL rs=0;
int wz=(l+r)>>1;
if(opl<=wz)rs=max(rs,query(ps<<1,l,wz));
if(opr>wz)rs=max(rs,query((ps<<1)|1,wz+1,r));
update(ps);
return rs;
}
int main(){
n=read();
fo(i,1,n){
j=read();k=read();l=read();
if(j==k)continue;
tot=tot+1;
c[tot].x=j,c[tot].y=k,c[tot].z=l;
}
fo(i,1,n)f[i]=i;
A=B=0;
fo(i,1,tot){
gx=get(c[i].x);
gy=get(c[i].y);
if(gx^gy){
lb(c[i].x,c[i].y,c[i].z);
lb(c[i].y,c[i].x,c[i].z);
f[gy]=gx;
}else{
A=c[i].x;
B=c[i].y;
D1=c[i].z;
}
}
dg(1);
if(A==0&&B==0){
dg1(1);
ans=0;
fo(i,1,n)ans=max(ans,mx[i]+cmx[i]);
ans++;
printf("%lld",ans);
return 0;
}
C=getlca(A,B);
chuli();
memset(fa,0,sizeof(fa));
fo(i,1,tot)bz[o[i]]=1;
fo(i,1,tot)dg1(o[i]);
fo(i,1,n)ans=max(ans,mx[i]+cmx[i]);
L1=1,R1=tot*3-2;
fo(i,1,tot)cd=cd+o1[i];
cd=cd+1ll*D1;
cd1=cd;
opz=cd;
fo(i,1,tot-1){
cd=cd-o1[i+1];
E[i]=cd;
opz=cd+mx[o[i+1]];
opl=opr=i;
change(1,1,R1);
}
cd=0;
fo(i,tot,tot+tot-1){
cd=cd+o1[i-tot+1];
E[i]=cd;
opz=cd+mx[o[i-tot+1]];
opl=opr=i;
change(1,1,R1);
}
cd=cd1;
fo(i,tot*2,tot*3-2){
cd=cd+o1[i-2*tot+1];
E[i]=cd;
opz=cd+mx[o[i-2*tot+1]];
opl=opr=i;
change(1,1,R1);
}
L1=tot;cd=0;
fo(i,tot,tot+tot-1){
cd=E[i];
while(L1<=R1){
D1=E[L1]-cd;
if(D1>cd1-D1)break;
L1++;
}
opl=i+1,opr=L1-1;
ans=max(ans,query(1,1,R1)+mx[o[i-tot+1]]);
opl=opr-tot+1,opr=i-1;
ans=max(ans,query(1,1,R1)+mx[o[i-tot+1]]);
opl=1,opr=i-1;opz=E[i+1]-E[i];
change(1,1,R1);
opl=i+1,opr=R1;opz=-(E[i+1]-E[i]);
change(1,1,R1);
}
ans++;
printf("%lld",ans);
return 0;
}