洛谷P1399 快餐店

題意:在基環樹上找一點,使得這個點到全部點的距離最大值最小。這個點能夠在某條邊上。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 }
AC代碼
相關文章
相關標籤/搜索