Solution to a problem luogu P5021 [construction] track

Solution to a problem luogu P5021 [construction] track

Time: 2019.8.9 20:40

Time: 2019.8.12

Title Description

C city will hold a series of racing. Before the game, we need to build in the city \ (m \) track.

City a total of C \ (n \) junctions, these junctions are numbered \ (1, 2, the n-\ DOTS, \) , there \ (n-1 \) strip suitable for the construction of two-way traffic on the road track, each road connects the two junctions. Wherein, the \ (I \) two junction roads connected number is \ (a_i \) and \ (B_i \) , the length of the road \ (L_i \) . With this \ (n-1 \) path, starting from any intersection can reach all the other intersection.

A track is a set of mutually different road \ (e_1, e_2, \ DOTS, E_k \) , may meet from a junction, passes through the road \ (e_1, e_2, \ DOTS, E_k \) (each after a road, do not allow U-turn) to reach another intersection. After a length equal to the length of the track of each road and. To ensure safety, the requirements of each road up to be a track through.

Currently the construction of the track program has not been determined. Your task is to design a circuit construction of the embodiment, so that the construction of \ (m \) track the maximum length of the minimum length of the track (i.e. \ (m \) the length of the shortest track in the track as much as possible)

Analysis of the meaning of problems

Given a \ (n-\) tree points, and wherein the selecting \ (m \) Article edge disjoint paths, so that the shortest path (track) in length as large as possible.

analysis

The length of the shortest path as large as possible, i.e. maximizing the minimum requirements. Obviously you can consider half.

Consider converted to binary decision problems: bipartite enumeration \ (limit \) , you can select \ (m \) section length is not less than \ (limit \) path?

Might as much as possible to select the length of not less than \ (limit \) path, determines whether the selected number greater than or equal to the maximum \ (m \) .

So, our problem is further converted to: give \ (limit \) , obtained not less than \ (limit \) path up to how many.

Greedy strategy

First gave a definition: from \ (u \) subtree of a node connected to the \ (u \) in a path called "semi-chain" (borrowed @ XG_Zepto defined)

Here is an example of a half link. We found two lengths of greater than or equal \ (limit \) unused half chain (red) can be combined together to create contribution to the answer.

1.png

As shown, A and B are not used two half link. If the total length A and B can reach \ (limit \) , then they are combined, resulting in a contribution to the answer.

  • It is easy to imagine: two and a half each time try to make the total length of the chain when the merger close \ (limit \) , this time can be better. In other words, let the legal total length as small as possible better .

  • In addition, if \ (v \) is (u \) \ son, if \ (v \) subtree chain can be combined with two and a half, then do not you want to link a certain (plus \ (u, v \) after the distance) to stay \ (u \) merge at.

    This is because the cause of a semi-chain up to answer \ (1 \) contributions, and \ (v \) can only leaving a return to \ (U \) , and the answer will not do it better. In other words, it can be combined as far as possible in the combined subtree subtree .

With these two greedy strategy, we consider recursively traverse the entire tree. Access to \ (u \) when the number of nodes, we first \ (u \) sons of the sub-tree, half chain can merge as much as possible the merger, and the combined cumulative number to answer. When a son return from, nothing more than two situations:

  1. The son subtree does not match the two half-chains combined. The remaining half or chain length is too small, or an insufficient number of (odd number).
  2. Subtree half link has paired off, and no remaining half link.

Respective solutions are as follows:

  1. Select a maximum of half the remaining half link chain, which length plus \ (u, v \) after the return distance. (A son return up to half a chain)
  2. Returned directly \ (u, v \) distance.

In fact, we do not need to know the whole story semi-node chain. We only need to know the chain length and a half on the line (Well anyway, certainly can be combined).

The combined method

Having said that, specifically how to do it?

If we have access to the \ (u \) number of nodes, the first \ (u \) of all recursive traversal son. Each son will return length of one half of the chain. We will keep all of these into a length of vectoryears.

And then merge the data. The combined method is not a time to find two less than the sum of \ (limit \) data, the answer will accumulate \ (1 \) , and delete the two data.

We want to ensure that the merger will not miss some legitimate program, but also the chain length of the semi-final return as much as possible as long as possible. The first is from small to large match (answer does not make worse, but also to avoid the biggest first half chain is deleted). You might think of ordering and using double pointer method (two-pointers), unfortunately, double Finger miss some cases.

why? A reference to the following examples. Let's assume that two-pointer from small to large law merge it, that is, long code may look like this (reducing the number of special sentence):

// vector<int> v; n = v.size();
sort(v.begin(), v.end()); // 从小到大排序
int cur = n - 1;
for (int i = 0; i < n; i++) {
  if (used[i]) continue;
  while (used[cur] && v[i] + v[cur - 1] >= limit)
    cur--;
  if (v[i] + v[cur] >= limit) {
    ans++;
    used[i] = used[cur] = true;
  }
  if (i + 1 == cur) break;
}

In order to make combined total length as small as possible, when v[i] + v[cur - 1] >= limitthe time constantly cur--. And it looks like no problem, each half chain \ (i \) will find the matching half of the minimum chain \ (CUR \) . The Code even after a sample. We look at a set of data:

v: 1 2 3 3 3 4
limit = 5

Very simple, is not it? If you use a double pointer, what will happen then?

  • 1And 4paired,cur--
  • 2And 3matching, because 2each 3can be paired according to our algorithm, we make 2and the leftmost 3pair.
  • Well, this time, \ (i \) points 2, while \ (cur \) points to the far left 3, because \ (i \) and \ (cur \) collided loop exits and returns the rest of the numbers in maximum3

Find out what the problem? He skipped when moving the pointer 3and 3the data in both the original can be combined. solution? The \ (cur \) moved to the end? Let 2and rightmost 3pair? Descending pairing? Unfortunately, not work. Hack data can be easily constructed. The problem is that the double pointer skip numbers can not come back.

Use balanced tree / multiset

And then look at our mission: to find a time not less than the sum of the two \ (limit \) data, the answer will accumulate \ (1 \) , and delete the two data.

Using a balanced tree on the line Well! Continue to traverse the minimum data \ (the X-\) , then find a balanced tree than the first \ ((limit - x) \ ) a large number \ (the y-\) , the answer will accumulate \ (1 \) , last will \ (x \) and \ (y \) deleted until a balanced tree size does not exceed \ (\ 1) so far.

Of course, we do not need a balanced tree handwriting. STL inside multisetenough to solve this problem.

multiset::lower_bound(x)Returns a greater than or equal \ (X \) is the number of \ (Y \) (iterator). If you do not know what iterators, you can understand it more as a clever pointer (funny). *iterThe syntax works for iterators.

Well, the following code can replace this share above the double pointer code.

// multiset<int> son[u]
while (!son[u].empty()) {
  LL x = *(son[u].begin());
  son[u].erase(son[u].begin());
  Iter iter = son[u].lower_bound(limit - x);
  if (iter == son[u].end()) {
    ans.val = max(ans.val, x);
  } else {
    ans.cnt++;
    son[u].erase(iter);
  }
}

Here is the process to find and remove. Note that if lower_boundthe returned iterator equals son[u].end()then could not be found. At this time it is updated with \ (U \) to be returned half the longest chain length. If there is no data update half the longest chain length, it is set to \ (0 \) . Plus \ (u, v \) from this step in the process will be fathers.

Code

Note that a small detail: if a length of half-chain is greater than or equal \ (limit \) , then this can be a semi-separate chain path (not combined).

Code actually quite short qwq.

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
typedef multiset<LL>::iterator Iter;
const int kMaxN = 50000 + 10;
struct Graph {
  struct Arc {
    int to;
    LL dis;
  };
  vector<Arc> arcs[kMaxN];
  void Add(int u, int v, LL dis) {
    arcs[u].push_back((Arc) {v, dis});
    arcs[v].push_back((Arc) {u, dis});
  }
};
struct Info {
  int cnt;
  LL val;
};
Graph G;
int n, m;
LL limit, max_limit;
multiset<LL> son[kMaxN];
Info Dfs(int u, int fa) {
  Info ans = (Info) {0, 0ll};
  son[u].clear();
  for (int i = 0; i < G.arcs[u].size(); i++) {
    Graph::Arc& arc = G.arcs[u][i];
    int v = arc.to;
    if (v != fa) {
      Info res = Dfs(v, u);
      res.val += arc.dis;
      ans.cnt += res.cnt;
      if (res.val >= limit) {
        ans.cnt++;
      } else {
        son[u].insert(res.val);
      }
    }
  }
  while (!son[u].empty()) {
    LL x = *(son[u].begin());
    son[u].erase(son[u].begin());
    Iter iter = son[u].lower_bound(limit - x);
    if (iter == son[u].end()) {
      ans.val = max(ans.val, x);
    } else {
      ans.cnt++;
      son[u].erase(iter);
    }
  }
  return ans;
}
int main() {
  scanf("%d %d", &n, &m);
  for (int i = 1; i <= n - 1; i++) {
    int u, v, w;
    scanf("%d %d %d", &u, &v, &w);
    G.Add(u, v, w);
    max_limit += w;
  }
  LL end = 0, top = max_limit + 1;
  while (end + 1 != top) {
    limit = (end + top) >> 1;
    int count = Dfs(1, 0).cnt;
    if (count >= m) {
      end = limit;
    } else {
      top = limit;
    }
  }
  printf("%lld\n", end);
  return 0;
}

Guess you like

Origin www.cnblogs.com/longlongzhu123/p/11361134.html