LOJ2324. 「清华集训 2017」小 Y 和二叉树【贪心】【DP】【思维】【好】

LINK


思路

首先贪新的思路是处理出以一个节点为根所有儿子的子树中中序遍历起始节点最小是多少
然后这个可以两次dfs来DP处理
然后就试图确定中序遍历的第一个节点
一定是siz<=2的编号最小的节点
这样肯定是最小的
那么来考虑从这个节点向右上和右下方扩展整棵树
一定是不能向左上或左下,不然就不优秀了
如果当前节点右除了左下有两个儿子,那么最小值小的放在右下,递归处理,大的放在右上,递归处理
如果只有一个儿子,就比较儿子和当前节点的大小并递归处理就可以了

好题啊


//Author: dream_maker
#include<bits/stdc++.h>
using namespace std;
//----------------------------------------------
//typename
typedef long long ll;
typedef pair<int, int> pi;
//convenient for
#define fu(a, b, c) for (int a = b; a <= c; ++a)
#define fd(a, b, c) for (int a = b; a >= c; --a)
#define fv(a, b) for (int a = 0; a < (signed)b.size(); ++a)
//inf of different typename
const int INF_of_int = 1e9;
const ll INF_of_ll = 1e18;
//fast read and write
template <typename T>
void Read(T &x) {
  bool w = 1;x = 0;
  char c = getchar();
  while (!isdigit(c) && c != '-') c = getchar();
  if (c == '-') w = 0, c = getchar();
  while (isdigit(c)) {
    x = (x<<1) + (x<<3) + c -'0';
    c = getchar();
  }
  if (!w) x = -x;
}
template <typename T>
void Write(T x) {
  if (x < 0) {
    putchar('-');
    x = -x; 
  }
  if (x > 9) Write(x / 10);
  putchar(x % 10 + '0');
}
//----------------------------------------------
const int N = 1e6 + 10;
int n, siz[N];
int ans[N], now[N], cnt;
int f[N][4], ch[N][4], anc[N];
int dfs1(int u, int fa) {
  int res = INF_of_int;
  fu(i, 1, siz[u]) {
    int v = ch[u][i];
    if (v == fa) {
      anc[u] = i;
      continue;
    }
    f[u][i] = dfs1(v, u);
    res = min(res, f[u][i]);
  }
  if (siz[u] == 1 && fa) return u;
  if (siz[u] == 2 && fa) return min(u, res);
  return res;
}
void dfs2(int u) {
  int minv = INF_of_int, fa = ch[u][anc[u]];
  fu(i, 1, siz[fa]) {
    int v = ch[fa][i]; 
    if (v == u) continue;
    minv = min(minv, f[fa][i]);
  }
  if (siz[fa] <= 2) minv = min(minv, fa);
  f[u][anc[u]] = minv;
  fu(i, 1, siz[u]) {
    int v = ch[u][i];
    if (v == fa) continue;
    dfs2(v);
  }
}
void getnow(int u, int fa) {
  pi tmp[4];
  int ind = 0;
  fu(i, 1, siz[u]) {
    int v = ch[u][i];
    if (v == fa) continue;
    tmp[++ind] = pi(f[u][i], i);
  }
  if (!ind) {
    ans[++cnt] = u;
    return;
  }
  sort(tmp + 1, tmp + ind + 1);
  if (ind == 1) {
    if (f[u][tmp[1].second] < u) {
      getnow(ch[u][tmp[1].second], u);
      ans[++cnt] = u;
    } else {
      ans[++cnt] = u;
      getnow(ch[u][tmp[1].second], u);
    }
  } else {
    getnow(ch[u][tmp[1].second], u);
    ans[++cnt] = u;
    getnow(ch[u][tmp[2].second], u);
  }
}
void solve(int u, int fro) {
  ans[++cnt] = u;
  pi tmp[4];
  int ind = 0;
  fu(i, 1, siz[u]) {
    int v = ch[u][i];
    if (v == fro) continue;
    tmp[++ind] = pi(f[u][i], i);
  }
  if (!ind) return;
  sort(tmp + 1, tmp + ind + 1);
  if (ind == 1) {
    int nxt = ch[u][tmp[1].second];
    int minv = INF_of_int;
    fu(i, 1, siz[nxt])
      if (ch[nxt][i] != u) minv = min(minv, f[nxt][i]);
    if (minv < nxt) {
      getnow(nxt, u);
    } else {
      solve(nxt, u);
    }
  } else {
    getnow(ch[u][tmp[1].second], u);
    solve(ch[u][tmp[2].second], u);
  } 
}
int main() {
  Read(n);
  fu(i, 1, n) {
    Read(siz[i]);
    fu(j, 1, siz[i]) Read(ch[i][j]);
  }
  dfs1(1, 0);
  dfs2(1);
  fu(i, 1, n) ans[i] = n;
  int pos = 0;
  fu(i, 1, n)
    if (siz[i] <= 2) {pos = i; break;}
  solve(pos, 0);
  fu(i, 1, n) {
    Write(ans[i]);
    putchar(' ');
  }
  return 0;
}
posted @ 2018-10-01 21:03  Dream_maker_yk  阅读(237)  评论(0编辑  收藏  举报