题意:在基环树上找一点,使得这个点到所有点的距离最大值最小。这个点可以在某条边上。
解:很容易想到找出直径然后/2对吧...这里的直径是指任意两点间最短距离的最大值。
然而我这个SB冥思苦想了半天之后想到了一个傻逼绝伦的做法:枚举边!
这个点一定在某条边上。
所以知道边的两端点最长延伸多长即可。
如果是子树里的边,很显然下面那个点就是子树内最长链。而上面那个点就是子树外最长链或深度 + 根节点在环上最长延伸距离。
如果是环上的边,就是两端点子树最长链或者环上延伸的最长距离。
值得注意的是,这两个"环上最长延伸距离"并不是一样的。
因为前者只有一个点在环上,没有别的环上的点跟它竞争。
而后者要跟环上另一个点相互竞争。所以还要分两种情况。
具体实现上,首先找环,然后每个子树做两次树形DP,第二次是二次扫描与换根法。
然后把环的信息提取出来DP,利用单调队列来求最长延伸距离,反正我写了4个......
最后枚举边判定。
反正就是仔细写,耐心Debug...
(为什么别人1k就能A而我要5k啊...)
1 #include <cstdio> 2 #include <algorithm> 3 #include <stack> 4 #include <cstring> 5 6 typedef long long LL; 7 const int N = 200010; 8 9 struct Edge { 10 int nex, v; 11 LL len; 12 }edge[N << 1]; int top = 1; 13 14 int e[N], n, cir[N], tc, p[N], head, tail, fr[N], nex[N], pre[N]; 15 std::stack<int> S; 16 bool vis[N], is_cir[N]; 17 LL d[N], len1[N], len2[N], lenup[N], dis[N], p2[N], sum[N], Long[N], Long_l[N], Long_r[N]; 18 19 inline void add(int x, int y, LL z) { 20 top++; 21 edge[top].v = y; 22 edge[top].len = z; 23 edge[top].nex = e[x]; 24 e[x] = top; 25 return; 26 } 27 28 void Df(int x, int f) { 29 vis[x] = 1; 30 S.push(x); 31 for(int i = e[x]; i && !vis[0]; i = edge[i].nex) { 32 int y = edge[i].v; 33 if(y == f) { 34 continue; 35 } 36 if(vis[y]) { 37 vis[0] = 1; 38 while(x != y) { 39 x = S.top(); 40 S.pop(); 41 is_cir[x] = 1; 42 cir[++tc] = x; 43 } 44 return; 45 } 46 Df(y, x); 47 } 48 if(vis[0]) { 49 return; 50 } 51 S.pop(); 52 vis[x] = 0; 53 return; 54 } 55 56 void DFS_1(int x, int f, int aim) { // get d len1 len2 57 if(!fr[x]) { 58 fr[x] = fr[f]; 59 } 60 for(int i = e[x]; i; i = edge[i].nex) { 61 int y = edge[i].v; 62 if(y == f || is_cir[y]) { 63 if(cir[aim] == y) { 64 dis[aim] = edge[i].len; 65 nex[x] = y; 66 pre[y] = x; 67 } 68 continue; 69 } 70 d[y] = d[x] + edge[i].len; 71 DFS_1(y, x, aim); 72 if(len1[x] < len1[y] + edge[i].len) { 73 len2[x] = len1[x]; 74 len1[x] = len1[y] + edge[i].len; 75 } 76 else if(len2[x] < len1[y] + edge[i].len) { 77 len2[x] = len1[y] + edge[i].len; 78 } 79 } 80 return; 81 } 82 83 void DFS_2(int x, int f) { 84 for(int i = e[x]; i; i = edge[i].nex) { 85 int y = edge[i].v; 86 if(y == f || is_cir[y]) { 87 continue; 88 } 89 if(len1[y] + edge[i].len == len1[x]) { 90 lenup[y] = std::max(lenup[x], len2[x]) + edge[i].len; 91 } 92 else { 93 lenup[y] = std::max(lenup[x], len1[x]) + edge[i].len; 94 } 95 DFS_2(y, x); 96 } 97 return; 98 } 99 100 int main() { 101 int x, y; 102 LL z, Sum = 0; 103 double ans = 0; 104 scanf("%d", &n); 105 for(int i = 1; i <= n; i++) { 106 scanf("%d%d%lld", &x, &y, &z); 107 add(x, y, z); 108 add(y, x, z); 109 ans += z; 110 } 111 Df(1, 0); 112 113 for(int i = 1; i <= tc; i++) { 114 fr[cir[i]] = cir[i]; 115 DFS_1(cir[i], 0, (i == tc ? 1 : i + 1)); 116 DFS_2(cir[i], 0); 117 cir[tc + i] = cir[i]; 118 } 119 for(int i = 1; i <= tc; i++) { 120 Sum += dis[i]; 121 dis[tc + i] = dis[i]; 122 } 123 for(int i = 1; i <= tc * 2; i++) { 124 sum[i] = sum[i - 1] + dis[i]; 125 } 126 127 LL dt = 0; 128 head = 1; 129 tail = 0; 130 for(int i = 1; i <= tc * 2; i++) { 131 // DP 132 while(head <= tail && sum[i] - sum[p[head]] > Sum - (sum[i] - sum[p[head]])) { 133 head++; 134 } 135 dt += dis[i]; 136 if(head <= tail) { 137 Long[cir[i]] = std::max(Long[cir[i]], p2[head] + dt); 138 } 139 while(head <= tail && len1[cir[i]] - dt >= p2[tail]) { 140 tail--; 141 } 142 p[++tail] = i; 143 p2[tail] = len1[cir[i]] - dt; 144 } 145 head = 1; 146 tail = 0; 147 dt = 0; 148 for(int i = tc * 2; i >= 1; i--) { 149 while(head <= tail && sum[p[head]] - sum[i] > Sum - (sum[p[head]] - sum[i])) { 150 head++; 151 } 152 dt += dis[i + 1]; 153 if(head <= tail) { 154 Long[cir[i]] = std::max(Long[cir[i]], p2[head] + dt); 155 } 156 while(head <= tail && len1[cir[i]] - dt >= p2[tail]) { 157 tail--; 158 } 159 p[++tail] = i; 160 p2[tail] = len1[cir[i]] - dt; 161 } 162 // ------------------------------------------------------------------------------------------------------- 163 head = 1; 164 tail = 0; 165 dt = 0; 166 dis[tc * 2 + 1] = dis[1]; 167 for(int i = 1; i <= tc * 2; i++) { 168 // DP 169 while(head <= tail && sum[i] - sum[p[head]] > Sum - (sum[i] - sum[p[head]] + dis[i + 1])) { 170 head++; 171 } 172 dt += dis[i]; 173 if(head <= tail) { 174 Long_l[cir[i]] = std::max(Long_l[cir[i]], p2[head] + dt); 175 } 176 while(head <= tail && len1[cir[i]] - dt >= p2[tail]) { 177 tail--; 178 } 179 p[++tail] = i; 180 p2[tail] = len1[cir[i]] - dt; 181 } 182 head = 1; 183 tail = 0; 184 dt = 0; 185 for(int i = tc * 2; i >= 1; i--) { 186 while(head <= tail && sum[p[head]] - sum[i] > Sum - (sum[p[head]] - sum[i - 1])) { 187 head++; 188 } 189 dt += dis[i + 1]; 190 if(head <= tail) { 191 Long_r[cir[i]] = std::max(Long_r[cir[i]], p2[head] + dt); 192 } 193 while(head <= tail && len1[cir[i]] - dt >= p2[tail]) { 194 tail--; 195 } 196 p[++tail] = i; 197 p2[tail] = len1[cir[i]] - dt; 198 } 199 // 200 for(int i = 2; i <= top; i += 2) { 201 int x = edge[i].v, y = edge[i ^ 1].v; 202 LL a, b; 203 if(is_cir[x] && is_cir[y]) { 204 if(nex[y] == x) { 205 std::swap(x, y); 206 } 207 a = std::max(Long_l[x], len1[x]); 208 b = std::max(Long_r[y], len1[y]); 209 } 210 else { 211 if(d[x] > d[y]) { 212 std::swap(x, y); 213 } 214 a = len1[y]; 215 b = std::max(lenup[y] - edge[i].len, d[x] + Long[fr[x]]); 216 } 217 if(a < b) { 218 std::swap(a, b); 219 } 220 if(a >= edge[i].len + b) { 221 ans = std::min(ans, (double)a); 222 } 223 else { 224 ans = std::min(ans, (a + b + edge[i].len) / 2.0); 225 } 226 } 227 228 printf("%.1f", ans); 229 return 0; 230 }