智障初二小朋友,4.5kb代码去A别人600b代码A的题,复杂度还被std碾压 T_T 看来我这种智障不看题解就要完
我们考虑计算每条路径上黑色节点数的最大值,我们可以参考字典树的思想,将所有叶子节点到根节点路径上的点的 cnt + 1, 这样,最后那些 cnt 为 1 的点一定只会对一个叶子节点到根节点上的黑点数量产生影响 (dfs一遍不难实现) 知道了这一点的话,我们考虑如果在一个 cnt 不为 1 的点染色,那么一定会有多个点一起增加,所以我们只要找到到根 cnt 为 1 的点数量最少的叶子节点,将它到根节点的长度作为 Min, 再将 Min 对所有点到根的长度取min (保证合法性)
现在我们只需贪心地染色即可,由于染色的点越高,它就越能满足更多的点,所以我们贪心的染路径上最下面 Min 个点
具体细节是,为了避免非法情况,我们按照深度从小到大的顺序处理叶子节点,对于每个点先减去它到根已经染好的数量,再染剩下的
怎么维护?好问题,LCT? LCT! 4.5kb代码就是这么出来的 T_T
我们只需维护树上路径和,支持覆盖操作即可,找下面第 Min 个点可以直接找 Splay 中第 Min 大
复杂度 $O(Nlog_2N)$
#include <bits/stdc++.h>
using namespace std;
#define REP(i, a, b) for (int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define debug(...) fprintf(stderr, __VA_ARGS__)
#define print(...) printf(__VA_ARGS__), fflush(stdout)
#define mp make_pair
#define x first
#define y second
#define pb push_back
#define SZ(x) (int((x).size()))
#define ALL(x) (x).begin(), (x).end()
template<typename T> inline bool chkmin(T &a, const T &b) { return a > b ? a = b, 1 : 0; }
template<typename T> inline bool chkmax(T &a, const T &b) { return a < b ? a = b, 1 : 0; }
typedef long long LL;
inline int read()
{
register int c = getchar(), sum(0), fg(1);
while (c < '0' || c > '9') { if (c == '-') fg = -1; c = getchar(); }
while (c >= '0' && c <= '9') sum = sum * 10 + c - '0', c = getchar();
return sum * fg;
}
const int oo = 0x3f3f3f3f;
const int maxn = 100000, maxl = 20;
struct edge
{
int id, nxt;
edge(const int &_id = 0, const int &_nxt = 0): id(_id), nxt(_nxt) { }
};
edge e[(maxn << 1) + 5];
int st[maxn + 5], Count[maxn + 5], cnt;
inline void add(const int &x, const int &y, const int &type = 1)
{
++Count[y];
e[cnt] = edge(y, st[x]), st[x] = cnt++;
if (type) add(y, x, 0);
}
int Size;
struct LCT
{
int ch[maxn + 5][2], pre[maxn + 5], rev[maxn + 5], size[maxn + 5], val[maxn + 5], sum[maxn + 5], Set[maxn + 5];
#define L ch][0
#define R ch][1
inline bool is_root(const int &x) { return x[pre][L] != x && x[pre][R] != x; }
inline void push_up(const int &x)
{
x[size] = 1 + x[L][size] + x[R][size];
x[sum] = x[val] + x[L][sum] + x[R][sum];
}
inline void push_down(const int &x)
{
if (~x[Set])
{
if (x[L]) x[L][val] = x[Set], x[L][Set] = x[Set], x[L][sum] = x[Set] * x[L][size];
if (x[R]) x[R][val] = x[Set], x[R][Set] = x[Set], x[R][sum] = x[Set] * x[R][size];
x[Set] = -1;
}
if (x[rev])
{
if (x[L]) x[L][rev] ^= 1;
if (x[R]) x[R][rev] ^= 1;
swap(x[L], x[R]);
x[rev] = 0;
}
}
inline void rotate(const int x)
{
const int y = x[pre], T = x == y[R];
y[ch][T] = x[ch][!T];
if (x[ch][!T]) x[ch][!T][pre] = y;
x[pre] = y[pre];
if (y == y[pre][L]) y[pre][L] = x;
if (y == y[pre][R]) y[pre][R] = x;
x[ch][!T] = y, y[pre] = x;
push_up(y);
}
inline void push(const int &x)
{
if (!is_root(x)) push(x[pre]);
push_down(x);
}
inline void splay(const int &x)
{
push(x);
while (!is_root(x))
{
int y = x[pre], z = y[pre];
if (!is_root(y)) rotate((x == y[L]) ^ (y == z[L]) ? x : y);
rotate(x);
}
push_up(x);
}
inline int access(const int &x)
{
for (splay(x), x[R] = 0, push_up(x); x[pre]; splay(x))
{
splay(x[pre]);
x[pre][R] = x;
push_up(x[pre]);
}
return x;
}
inline void change_root(const int &x)
{
access(x)[rev] ^= 1;
}
inline void link(const int &x, const int &y)
{
access(y);
y[pre] = x;
access(y);
}
inline int locate(const int &x, const int &k)
{
if (k == x[R][size] + 1) return x;
if (k <= x[R][size]) return locate(x[R], k);
else return locate(x[L], k - x[R][size] - 1);
}
inline int query(const int &x)
{
access(x);
int ans = x[sum], y = locate(x, Size - ans);
change_root(x);
access(y);
y[Set] = 1, y[val] = 1, y[sum] = y[size];
change_root(1);
return ans;
}
}t;
int leaf[maxn + 5], sum[maxn + 5], dis[maxn + 5];
inline void build(const int &x, const int &fa)
{
if (x != 1 && Count[x] == 1)
{
sum[x] = 1;
return;
}
for (int i = st[x]; ~i; i = e[i].nxt)
{
int y = e[i].id;
if (y != fa)
{
t.link(x, y);
build(y, x);
sum[x] += sum[y];
}
}
}
int min_id[maxn + 5];
inline int dfs(const int &x, const int &fa)
{
if (x != 1 && Count[x] == 1)
{
min_id[x] = x;
return 1;
}
int Min = oo; min_id[x] = 0;
for (int i = st[x]; ~i; i = e[i].nxt)
{
int y = e[i].id;
if (y != fa)
{
dis[y] = dis[x] + 1;
chkmin(Min, dfs(y, x)) ? min_id[x] = min_id[y] : 0;
}
}
return Min + (sum[x] == 1);
}
int N, M;
struct Leaf
{
int x, y;
inline bool operator < (const Leaf &obj) const { return y < obj.y; }
Leaf(const int &_x = 0, const int &_y = 0): x(_x), y(_y) { }
}T[maxn +5];
int main()
{
#ifndef ONLINE_JUDGE
freopen("tree.in", "r", stdin);
freopen("tree.out", "w", stdout);
#endif
memset(st, -1, sizeof st), cnt = 0;
N = read();
if (N == 1)
{
puts("1");
return 0;
}
REP(i, 1, N) t.size[i] = 1, t.val[i] = 0, t.Set[i] = -1;
REP(i, 2, N)
{
int x = read(), y = read();
add(x, y);
}
M = 0;
build(1, 0);
dis[1] = 1, dfs(1, 0);
Size = dis[min_id[1]];
REP(i, 2, N)
if (Count[i] == 1)
T[++M] = Leaf(i, dis[i]);
sort(T + 1, T + M + 1);
REP(i, 1, M) leaf[i] = T[i].x;
REP(i, 1, M) chkmin(Size, dis[leaf[i]]);
int ans = 0;
REP(i, 1, M) ans += Size - t.query(leaf[i]);
printf("%d\n", ans);
return 0;
}