没有用大家用的单调队列,但大体思路一样,代码应该很好懂了
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
// typedef __int128 int128;
typedef pair<int , int > pii;
typedef unsigned long long ull;
namespace FastIO
{
// char buf[1 << 20], *p1, *p2;
// #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++)
template<typename T> inline T read(T& x) {
x = 0;
int f = 1;
char ch;
while (!isdigit(ch = getchar())) if (ch == '-') f = -1;
while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
x *= f;
return x;
}
template<typename T, typename... Args> inline void read(T& x, Args &...x_) {
read(x);
read(x_...);
return;
}
inline ll read() {
ll x;
read(x);
return x;
}
};
using namespace FastIO;
template<int N, int M>
class Graph {
private :
struct Edge {
int to, nt, wt;
Edge() {}
Edge(int to, int nt, int wt) : to(to), nt(nt), wt(wt) {}
}e[M];
int hd[N], cnte;
public :
inline void clear() { memset(hd, 0, sizeof(hd)), cnte = 0; }
inline void AddEdge(int u, int v, int w = 0) {
e[++cnte] = Edge(v, hd[u], w);
hd[u] = cnte;
}
inline int head(int u) { return hd[u]; }
inline int nt(int u) { return e[u].nt; }
inline int to(int u) { return e[u].to; }
inline int wt(int u) { return e[u].wt; }
};
const int MaxV = 1000010;
const int MaxE = 2000010;
int n;
Graph< MaxV, MaxE >G;
inline void Input() {
read(n);
int v, w;
for(int u = 1; u <= n; u++) {
read(v, w);
G.AddEdge(u, v, w);
G.AddEdge(v, u, w);
}
}
int onCir[MaxV], vis[MaxV], vise[MaxE];
int Cir[MaxV], tot;
ll dis[MaxV];
bool GetCircle(int u, int fa) {
// cout << u << '\n';
vis[u] = 1;
for(int i = G.head(u); i; i = G.nt(i)) {
int v = G.to(i);
if(vise[i]) continue;
if(i & 1) vise[i] = vise[i + 1] = 1;
else vise[i] = vise[i - 1] = 1;
// cout << u << ' ' << v << endl;
if(vis[v]) {
onCir[u] = 1; Cir[++tot] = u;
dis[0] = G.wt(i);
return true;
}
if(GetCircle(v, u)) {
onCir[u] = 1; Cir[++tot] = u;
dis[tot] = dis[tot - 1] + G.wt(i);
return true;
}
}
return false;
}
pair<ll , ll > Lp[MaxV];
ll dmt[MaxV];
void GetDiameter(int u, int fa) {
Lp[u] = make_pair(0, 0);
for(int i = G.head(u); i; i = G.nt(i)) {
int v = G.to(i);
if(onCir[v]) continue;
if(v == fa) continue;
GetDiameter(v, u);
if(Lp[v].first + G.wt(i) > Lp[u].first) {
Lp[u].second = Lp[u].first;
Lp[u].first = Lp[v].first + G.wt(i);
}
else if(Lp[v].first + G.wt(i) > Lp[u].second) {
Lp[u].second = Lp[v].first + G.wt(i);
}
dmt[u] = max(dmt[u], dmt[v]);
}
dmt[u] = max(dmt[u], Lp[u].first + Lp[u].second);
}
ll ans;
/*
no repet :
a[i] + a[j] + (dis[j] - dis[i])
a[i] - dis[i] + a[j] + dis[j]
is repet :
a[i] + a[j] + dis[n] - (dis[j] - dis[i])
a[i] + dis[i] + dis[n] + a[j] - dis[j]
*/
ll dis2[MaxE];
inline void CalcCircle() {
// cout << dis[0] << endl;
// for(int i = 1; i <= tot; i++) {
// cout << Cir[i] << " : " << dis[i] << endl;
// }
ll mx = Lp[Cir[1]].first - dis[1];
for(int i = 2; i <= tot; i++) {
ans = max(ans, Lp[Cir[i]].first + dis[i] + mx);
// cout << Cir[i] << ' ' << Lp[Cir[i]].first + dis[i] + mx << endl;
mx = max(mx, Lp[Cir[i]].first - dis[i]);
}
dis[0] += dis[tot];
mx = Lp[Cir[1]].first + dis[1] + dis[0];
for(int i = 2; i <= tot; i++) {
ans = max(ans, Lp[Cir[i]].first - dis[i] + mx);
// cout << Cir[i] << ' ' << Lp[Cir[i]].first << ' ' << dis[i] << ' ' << mx << endl;
mx = max(mx, Lp[Cir[i]].first + dis[i] + dis[0]);
}
}
inline void Work() {
ll res = 0;
for(int i = 1; i <= n; i++) {
if(vis[i]) continue;
tot = 0; ans = 0;
GetCircle(i, i);
// cout << endl;
for(int u = 1; u <= tot; u++) {
GetDiameter(Cir[u], Cir[u]);
ans = max(ans, dmt[Cir[u]]);
// cout << Cir[u] << " : " << dmt[Cir[u]] << endl;
}
CalcCircle();
res += ans;
}
printf("%lld\n", res);
}
int main() {
int T = 1;
while(T--) {
Input();
Work();
}
return 0;
}