洛谷P1399 快餐店

题意:在基环树上找一点,使得这个点到所有点的距离最大值最小。这个点可以在某条边上。

解:很容易想到找出直径然后/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 }
AC代码

猜你喜欢

转载自www.cnblogs.com/huyufeifei/p/10339741.html