題意:在基環樹上找一點,使得這個點到全部點的距離最大值最小。這個點能夠在某條邊上。ide
解:很容易想到找出直徑而後/2對吧...這裏的直徑是指任意兩點間最短距離的最大值。spa
然而我這個SB左思右想了半天以後想到了一個傻逼絕倫的作法:枚舉邊!code
這個點必定在某條邊上。blog
因此知道邊的兩端點最長延伸多長便可。隊列
若是是子樹裏的邊,很顯然下面那個點就是子樹內最長鏈。而上面那個點就是子樹外最長鏈或深度 + 根節點在環上最長延伸距離。ci
若是是環上的邊,就是兩端點子樹最長鏈或者環上延伸的最長距離。get
值得注意的是,這兩個"環上最長延伸距離"並非同樣的。string
由於前者只有一個點在環上,沒有別的環上的點跟它競爭。it
然後者要跟環上另外一個點相互競爭。因此還要分兩種狀況。io
具體實現上,首先找環,而後每一個子樹作兩次樹形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 }