USACO20Feb Delegation P 【贪心】【二分答案】

跟Delegation G挺像的,还是贪心

二分答案套二分答案?

首先看到题目的求最小值最大,基本上可以确定二分答案,把最优问题变成可行问题

然后check的策略就是贪心,对于一个子树,如果他有奇数个子树,那么贪心的留一个最大长度的子树给祖先匹配,剩下的子树自己匹配,如果有偶数个子树,添加一个长度为0的子树即可

可以用再用一个二分答案确定留给祖先的子树,自己匹配部分贪心最小配最大即可

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <vector>
#define gi get_int()
const int MAXN = 2e5;
int get_int()
{
  int x = 0, y = 1;
  char ch = getchar();
  while (!isdigit(ch) && ch != '-')
    ch = getchar();
  if (ch == '-') 
    y = -1, ch = getchar();
  while (isdigit(ch))
    x = x * 10 + ch - '0', ch = getchar();
  return x * y;
}

class Edge
{
public:
  int next, to;
} edges[MAXN];
int head[MAXN], eNum;
void addEdge(int from, int to)
{
  edges[eNum] = (Edge) {head[from], to};
  head[from] = eNum++;
}

int mid;
int len[MAXN];
std::vector<int> num[MAXN];

int check(int now, int save, int nNum)
{
  for (int i = 0, j = nNum - 1; i < j; i++, j--) {
    if (i == save) i++;
    if (j == save) j--;
    if (num[now][i] + num[now][j] < mid) return false;
  }
  return true;
}

int dfs(int now = 0, int pre = -1)
{
  num[now].clear();
  for (int i = head[now]; i != -1; i = edges[i].next) {
    int to = edges[i].to;
    if (to == pre) continue;
    if (dfs(to, now) == false)
      return false;
    num[now].push_back(len[to] + 1);
  }
  int cnt = num[now].size();
  if ((pre != -1 && cnt % 2 == 0) || (pre == -1 && cnt % 2 != 0)) {
    num[now].push_back(0);
    cnt++;
  }
  std::sort(num[now].begin(), num[now].end());
  if (pre == -1)
    return check(now, -1, cnt);
  if (check(now, 0, cnt) == false) return false;
  int l = 0, r = cnt - 1, ans = 0;
  while (l <= r) {
    int midInside = (l + r) / 2;
    if (check(now, midInside, cnt) == true) {
      ans = num[now][midInside];
      l = midInside + 1;
    } else {
      r = midInside - 1;
    }
  }
  len[now] = ans;
  return true;
}

int main()
{
  freopen("code.in", "r", stdin);
  freopen("code.out", "w", stdout);

  int n = gi;
  memset(head, -1, sizeof(head));
  for (int i = 1; i < n; i++) {
    int from = gi - 1, to = gi - 1;
    addEdge(from, to);
    addEdge(to, from);
  }
  int l = 0, r = 1e8, ans = -1;
  while (l <= r) {
    mid = (l + r) / 2;
    if (dfs() == true) {
      l = mid + 1;
      ans = mid;
    } else {
      r = mid - 1;
    }
  }
  std::cout << ans;

  return 0;
}
posted @ 2021-05-20 09:26  enisp  阅读(55)  评论(0)    收藏  举报