本题是基环树模板题,但是有一点要注意,特判两元环是必要的
因为两元环中,我们要选权值大的两条边组成的直径,而多元环则不用在意,因为每两个点之间只有一条边
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=1e6+1e5; const int mod=998244353; int h[N],ne[N*2],e[N*2],w[N*2],idx; int vis[N],st[N]; ll d[N],dt[N]; int id[N]; ll a[N*2],b[N*2]; queue<int> q; int in[N]; void add(int a,int b,int c){ e[idx]=b,ne[idx]=h[a],w[idx]=c,h[a]=idx++; } void dfs0(int u,int fa){ st[u]=1; if(in[u]==1) q.push(u); for(int i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(st[j]) continue; dfs0(j,u); } } ll res; int topo(){ int x; while(q.size()){ int t=q.front(); q.pop(); vis[t]=1; for(int i=h[t];i!=-1;i=ne[i]){ int j=e[i]; if(vis[j]) continue; res=max(res,dt[t]+dt[j]+w[i]); dt[j]=max(dt[j],dt[t]+w[i]); in[j]--; if(in[j]==1){ q.push(j); } else{ x=j; } } } return x; } int visc[N]; int num; void dfs(int u,int fa){ visc[u]=1; id[++num]=u; int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa||vis[j]||visc[j]) continue; d[j]=d[u]+w[i]; dfs(j,u); } } int qq[N]; ll solve(int u){ res=0; int x=u; if(q.size()) x=topo(); num=0; dfs(x,x); ll len=d[id[num]]; int cnt=0; if(num==2){ int sum=0; for(int i=h[id[num]];i!=-1;i=ne[i]){ int j=e[i]; if(j==id[1]){ sum=max(sum,w[i]); } } len+=sum; } else{ for(int i=h[id[num]];i!=-1;i=ne[i]){ int j=e[i]; if(j==id[1]){ len+=w[i]; break; } } } //cout<<len<<endl; for(int i=1;i<=num;i++){ a[i]=dt[id[i]]; a[i+num]=dt[id[i]]; b[i]=d[id[i]]; b[i+num]=len+d[id[i]]; } int hh=0,tt=-1; for(int i=1;i<=2*num;i++){ while(hh<=tt&&i-qq[hh]>=num) hh++; if(hh<=tt) res=max(res,1ll*a[i]+b[i]+a[qq[hh]]-b[qq[hh]]); while(hh<=tt&&(a[i]-b[i])>=a[qq[tt]]-b[qq[tt]]) tt--; qq[++tt]=i; } return res; } int main(){ //ios::sync_with_stdio(false); memset(h,-1,sizeof h); int i; int n; cin>>n; for(i=1;i<=n;i++){ int u,v; scanf("%d%d",&u,&v); add(i,u,v); add(u,i,v); in[u]++; in[i]++; } ll ans=0; for(i=1;i<=n;i++){ if(!st[i]){ dfs0(i,-1); ans+=solve(i); } } cout<<ans<<endl; return 0; }