如果给的是一棵树那么答案显然是直径/2
但是现在给的是一个环套树 那你就枚举一下环上的每条边把它删掉再求直径就好辣(显然你不会走环上的某一条边 这很显然吧- - )
然后你就要求剩下来的这棵树的直径 然后n^2会爆炸 怎么办捏
我们维护以环上节点为根的树的最长链s
环上两点距离可以用前缀和处理(先假设枚举的第一条边是环上第一个点和最后一个点的边 这样就可以用前缀和表示了)
则直径为max(sum[j]-sum[i]+s[i]+s[j])
用一棵线段树维护sum[i] - s[i] 和 sum[i] + s[i]
但是i, j不能相同 所以在线段树中再维护一个次大值即可
删边的时候修改一下sum数组 修改一下线段树即可
#include
#include
#include
#include
#include
#define SF scanf
#define PF printf
#define ls (i<<1)
#define rs (i<<1|1)
using namespace std;
typedef long long LL;
inline int read() {
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
return x * f;
}
const int MAXN = 100000;
struct Node {
int v, wt, next;
} Edge[MAXN*2+10];
int adj[MAXN+10], ecnt;
void addedge(int u, int v, int wt) {
Node &e = Edge[++ecnt];
e.v = v; e.wt = wt; e.next = adj[u]; adj[u] = ecnt;
}
bool iscir[MAXN+10];
LL sum[MAXN+10], dis[MAXN+10], d[MAXN+10], ld[MAXN+10], rd[MAXN+10], tot, ans, mx;
int cc, cir[MAXN+10], fa[MAXN+10], vis[MAXN+10], n, p;
struct Seg_Tree {
LL mx1[MAXN*4+10], mx2[MAXN*4+10];
int p1[MAXN*4+10], p2[MAXN*4+10];
void up(int i) {
if(mx1[ls] > mx1[rs]) {
mx1[i] = mx1[ls];
p1[i] = p1[ls];
mx2[i] = mx1[rs];
p2[i] = p1[rs];
}
else {
mx1[i] = mx1[rs];
p1[i] = p1[rs];
mx2[i] = mx1[ls];
p2[i] = p1[ls];
}
if(mx2[ls] > mx2[i]) {
mx2[i] = mx2[ls];
p2[i] = p2[ls];
}
if(mx2[rs] > mx2[i]) {
mx2[i] = mx2[rs];
p2[i] = p2[rs];
}
}
void build(int i, int l, int r) {
if(l == r) {
mx1[i] = sum[l] + dis[l]; p1[i] = l;
mx2[i] = p2[i] = 0;
return ;
}
int mid = l+r >> 1;
build(ls, l, mid);
build(rs, mid+1, r);
up(i);
}
void ins(int i, int x, LL v, int L = 1, int R = cc) {
if(L == R) {
mx1[i] = v;
return ;
}
int mid = L+R >> 1;
if(x <= mid) ins(ls, x, v, L, mid);
else ins(rs, x, v, mid+1, R);
up(i);
}
} T;
struct Seg_Tree2 {
LL mx1[MAXN*4+10], mx2[MAXN*4+10];
int p1[MAXN*4+10], p2[MAXN*4+10];
void up(int i) {
if(mx1[ls] > mx1[rs]) {
mx1[i] = mx1[ls];
p1[i] = p1[ls];
mx2[i] = mx1[rs];
p2[i] = p1[rs];
}
else {
mx1[i] = mx1[rs];
p1[i] = p1[rs];
mx2[i] = mx1[ls];
p2[i] = p1[ls];
}
if(mx2[ls] > mx2[i]) {
mx2[i] = mx2[ls];
p2[i] = p2[ls];
}
if(mx2[rs] > mx2[i]) {
mx2[i] = mx2[rs];
p2[i] = p2[rs];
}
}
void build(int i, int l, int r) {
mx1[i] = mx2[i] = -10000000000000000LL;
if(l == r) {
mx1[i] = dis[l] - sum[l]; p1[i] = l;
return ;
}
int mid = l+r >> 1;
build(ls, l, mid);
build(rs, mid+1, r);
up(i);
}
void ins(int i, int x, LL v, int L = 1, int R = cc) {
if(L == R) {
mx1[i] = v;
return ;
}
int mid = L+R >> 1;
if(x <= mid) ins(ls, x, v, L, mid);
else ins(rs, x, v, mid+1, R);
up(i);
}
} Q;
bool dfs(int u, int pre) {
fa[u] = pre;
vis[u] = 1;
for(int i = adj[u]; i; i = Edge[i].next) {
int v = Edge[i].v;
if(v == pre) continue;
if(vis[v]) {
cir[1] = v;
fa[v] = u;
return true;
}
if(dfs(v, u)) return true;
}
return false;
}
void Find_circle() {
dfs(1, 0);
int u = cir[1];
while(fa[u] != cir[1]) {
cir[++cc] = fa[u];
u = fa[u];
}
for(int i = 1; i <= cc; i++) {
iscir[cir[i]] = true;
for(int j = adj[cir[i]]; j; j = Edge[j].next) {
int v = Edge[j].v, wt = Edge[j].wt;
if(v == cir[i%cc+1]) {
ld[i] = rd[i%cc+1] = wt;
tot += wt;
break;
}
}
}
for(int i = 2; i <= cc; i++) sum[i] = sum[i-1] + rd[i];
}
void DFS(int u, int pre) {
for(int i = adj[u]; i; i = Edge[i].next) {
int v = Edge[i].v, wt = Edge[i].wt;
if(v == pre || iscir[v]) continue;
d[v] = d[u] + wt;
if(d[v] > d[p]) p = v;
DFS(v, u);
}
}
void Find_dis(int x) {
int tmp;
d[cir[x]] = p = 0;
DFS(cir[x], 0);
tmp = p;
dis[x] = d[p];
iscir[cir[x]] = false;
d[tmp] = p = 0;
DFS(tmp, 0);
ans = max(ans, d[p]);
iscir[cir[x]] = true;
}
int main() {
n = read();
for(int i = 1; i <= n; i++) {
int u, v, wt;
u = read(); v = read(); wt = read();
addedge(u, v, wt); addedge(v, u, wt);
}
Find_circle();
for(int i = 1; i <= cc; i++)
Find_dis(i);
T.build(1, 1, cc);
Q.build(1, 1, cc);
LL ANS = 10000000000000000LL;
for(int i = 1; i <= cc; i++) {
if(T.p1[1] != Q.p1[1]) ANS = min(ANS, T.mx1[1] + Q.mx1[1]);
else ANS = min(ANS, max(T.mx1[1]+Q.mx2[1], T.mx2[1]+Q.mx1[1]));
sum[i] = rd[i] + sum[(i>1) ? (i-1) : cc];
T.ins(1, i, dis[i]+sum[i], 1, cc);
Q.ins(1, i, dis[i]-sum[i], 1, cc);
}
PF("%.1lf\n", (double)max(ans, ANS)/ (double)2.0);
}