P4183 [USACO18JAN]Cow at Large P
题面自行看吧。。。
std
首先把当前奶牛的位置作为根。
令 表示 与最近的叶子的距离。
那么若奶牛在 ,无法走到 的子树内,当且仅当 。
由于要使答案最优,即让 管辖的节点尽可能多,若 满足上面条件, 也满足上面条件,那么优先选 。
那么上面条件可转化为: 且 。
于是,问题就转化为:对于一个 ,求有多少个 满足上述条件,求解的时间复杂度为 。
考虑优化。
令 表示 的度数, 表示 的子树大小。
我们发现 ,即 。
而一个子树的贡献只有 ,所以我们可以将式子转化为:,此时就已经自动选满足的且深度最小的了。
考虑再次优化:
对于这种无根树,我们可以想到用点分治,以当前分治中心为根,维护有多少个 满足 ,即 ,树状数组维护一下即可,注意链重合的情况。
时间复杂度为 。
#include <bits/stdc++.h>
using namespace std;
const int _ = 2e5 + 10;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9')
{
if (c == '-')
f = -1;
c = getchar();
}
while (c >= '0' && c <= '9')
x = x * 10 + (c - '0'), c = getchar();
return x * f;
}
int n;
int tot, head[_], to[_ << 1], nxt[_ << 1];
bool vis[_];
int g[_], siz[_], mx[_], deg[_], d[_], p[_], ans[_], rt, sum;
int cnt, o[_];
int c[_];
void update(int x, int val)
{
for(; x <= 2 * n; x += x & -x)
c[x] += val;
}
int query(int x)
{
int res = 0;
for(; x; x -= x & -x)
res += c[x];
return res;
}
void add(int u, int v)
{
to[++tot] = v;
nxt[tot] = head[u];
head[u] = tot;
}
void dfs1(int u, int fa)
{
siz[u] = 1;
for(int i = head[u]; i; i = nxt[i])
{
int v = to[i];
if(v == fa)
continue;
dfs1(v, u);
g[u] = min(g[u], g[v] + 1);
}
}
void dfs2(int u, int fa)
{
for(int i = head[u]; i; i = nxt[i])
{
int v = to[i];
if(v == fa)
continue;
g[v] = min(g[v], g[u] + 1);
dfs2(v, u);
}
}
void get_rt(int u, int fa)
{
siz[u] = 1, mx[u] = 0;
for(int i = head[u]; i; i = nxt[i])
{
int v = to[i];
if(vis[v] || v == fa)
continue;
get_rt(v, u);
siz[u] += siz[v];
mx[u] = max(mx[u], siz[v]);
}
mx[u] = max(mx[u], sum - siz[u]);
if(mx[u] < mx[rt])
rt = u;
}
void get_dis(int u, int fa)
{
o[++cnt] = u;
for(int i = head[u]; i; i = nxt[i])
{
int v = to[i];
if(v == fa || vis[v])
continue;
d[v] = d[u] + 1;
get_dis(v, u);
}
}
void calc(int u, int len, int mul)
{
d[u] = len, cnt = 0;
get_dis(u, 0);
for(int i = 1; i <= cnt; ++i)
update(g[o[i]] - d[o[i]] + n, 2 - deg[o[i]]);
for(int i = 1; i <= cnt; ++i)
{
update(g[o[i]] - d[o[i]] + n, -(2 - deg[o[i]]));
ans[o[i]] += query(d[o[i]] + n) * mul;
update(g[o[i]] - d[o[i]] + n, 2 - deg[o[i]]);
}
for(int i = 1; i <= cnt; ++i)
update(g[o[i]] - d[o[i]] + n, -(2 - deg[o[i]]));
}
void dfz(int u)
{
vis[u] = 1;
calc(u, 0, 1);
for(int i = head[u]; i; i = nxt[i])
{
int v = to[i];
if(vis[v])
continue;
calc(v, 1, -1);
rt = 0, sum = siz[v];
get_rt(v, u), dfz(rt);
}
}
signed main()
{
memset(g, 0x3f, sizeof g);
n = read();
int a, b;
for(int i = 1; i < n; ++i)
{
a = read(), b = read();
add(a, b), add(b, a);
deg[a]++, deg[b]++;
}
for(int i = 1; i <= n; ++i)
if(deg[i] == 1) g[i] = 0;
dfs1(1, 0), dfs2(1, 0);
rt = 0, sum = n, mx[0] = 2e9;
get_rt(1, 0), dfz(rt);
for(int i = 1; i <= n; ++i)
printf("%d\n", deg[i] == 1 ? 1 : ans[i]);
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122021