F. Dominant Indices
题意:给一颗以1为根的树,设 d [ u ] [ x ] d[u][x] d[u][x]为 u u u子树中距离 u u u为 x x x的点的数量,对于每个点 u u u,求最小的 x x x使得 d [ u ] [ x ] d[u][x] d[u][x]最大
解法:
线段树合并:对于每个子树,用一颗线段树维护其 d [ u ] [ x ] d[u][x] d[u][x]的最大值,然后向上走不停的线段树合并即可。
长链剖分:对于每个子树,用一个动态数组维护其 d [ u ] [ x ] d[u][x] d[u][x]所有情况,每次向上合并的时候,不停的把轻儿子的链合并到重儿子的链,每个点代表的深度的信息只会被合并一次,复杂度极其优秀
线段树合并
#include
using namespace std;
const int maxn = 1e6 + 6;
#define mid (l + r) / 2
int rt[maxn], ls[maxn * 21], rs[maxn * 21], dep[maxn];
int mx[maxn * 21], pos[maxn * 21], ans[maxn], cnt, n;
vector<int> G[maxn];
void pushup(int o)
{
mx[o] = max(mx[ls[o]], mx[rs[o]]);
if (mx[ls[o]] >= mx[rs[o]])
pos[o] = pos[ls[o]];
else
pos[o] = pos[rs[o]];
}
void up(int &o, int l, int r, int k, int v)
{
if (!o)
o = ++cnt;
mx[o] += v;
if (l == r)
{
pos[o] = l;
return;
}
if (k <= mid)
up(ls[o], l, mid, k, v);
else
up(rs[o], mid + 1, r, k, v);
pushup(o);
}
int merge(int &o, int pre, int l, int r)
{
if (!o || !pre)
return o | pre;
if (l == r)
{
mx[o] += mx[pre];
return o;
}
ls[o] = merge(ls[o], ls[pre], l, mid);
rs[o] = merge(rs[o], rs[pre], mid + 1, r);
pushup(o);
return o;
}
void dfs(int u, int fa)
{
dep[u] = dep[fa] + 1;
up(rt[u], 1, n, dep[u], 1);
for (auto v : G[u])
if (v != fa)
{
dfs(v, u);
rt[u] = merge(rt[u], rt[v], 1, n);
}
ans[u] = pos[rt[u]] - dep[u];
}
int main()
{
int u, v;
scanf("%d", &n);
for (int i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
for (int i = 1; i <= n; i++)
printf("%d\n", ans[i]);
}
长链剖分
#include
using namespace std;
const int maxn = 1e6 + 6;
vector<int> G[maxn], g[maxn];
int h[maxn], son[maxn], ans[maxn];
void dfs(int u, int fa)
{
for (auto v : G[u])
if (v != fa)
{
dfs(v, u);
if (h[v] + 1 > h[u])
{
h[u] = h[v] + 1;
son[u] = v;
}
}
if (!son[u])
{
g[u].push_back(1);
return;
}
ans[u] = ans[son[u]];
swap(g[u], g[son[u]]);
for (auto v : G[u])
if (v != fa && v != son[u])
{
int n = g[u].size();
int m = g[v].size();
for (int i = n - m; i < n; i++)
{
g[u][i] += g[v][i - (n - m)];
if (g[u][i] >= g[u][ans[u]])
ans[u] = i;
}
}
g[u].push_back(1);
if (g[u][ans[u]] == 1)
ans[u] = g[u].size() - 1;
}
int main()
{
int n, u, v;
scanf("%d", &n);
for (int i = 1; i < n; i++)
{
scanf("%d%d", &u, &v);
G[u].push_back(v);
G[v].push_back(u);
}
dfs(1, 0);
for (int i = 1; i <= n; i++)
printf("%d\n", h[i] - ans[i]);
}