首页 > 其他分享 >P4183 [USACO18JAN] Cow at Large P 题解

P4183 [USACO18JAN] Cow at Large P 题解

时间:2024-02-10 23:22:41浏览次数:18  
标签:USACO18JAN 结点 int 题解 len Large kMaxN 贝茜 dis

Description

贝茜被农民们逼进了一个偏僻的农场。农场可视为一棵有 \(N\) 个结点的树,结点分别编号为 \(1,2,\ldots, N\) 。每个叶子结点都是出入口。开始时,每个出入口都可以放一个农民(也可以不放)。每个时刻,贝茜和农民都可以移动到相邻的一个结点。如果某一时刻农民与贝茜相遇了(在边上或点上均算),则贝茜将被抓住。抓捕过程中,农民们与贝茜均知道对方在哪个结点。

请问:对于结点 \(i\,(1\le i\le N)\) ,如果开始时贝茜在该结点,最少有多少农民,她才会被抓住。

\(2\leq N\leq 7\times 10^4\)。

Solution

先考虑固定起点怎么做。

首先每个叶子一定是每次往父亲跳,那么设 \(len_i\) 表示 \(i\) 到 \(i\) 子树里叶子的最短距离。

那么如果 \(len_i>dis_i\),则无论 \(i\) 的子树怎么放都无法在 \(i\) 点拦截贝茜。否则只要在离 \(i\) 最近的点放一个奶牛就能在 \(i\) 点拦截且贝茜不可能走到 \(i\) 子树里的其他点。

容易发现这些放的奶牛是不重的。

所以答案就是所有 \(len_i\leq dis_i\) 且 \(len_{fa_{i}}>dis_{fa_i}\) 的 \(i\) 的个数。

这样做是 \(O(n^2)\) 的。


考虑优化。

继续固定起点。容易发现这个题目等价于问有多少个子树,子树的根 \(i\) 满足 \(len_i\leq dis_i\) 且 \(len_{fa_{i}}>dis_{fa_i}\)。

设 \(deg_i\) 表示 \(i\) 的度数。

则对于一个大小为 \(m\) 的子树 \(S\),且子树的根不为原树的根,那么 \(\sum_{u\in S}{deg_u}=2m-1\),转化一下就是:\(\sum_{u\in S}{(2-deg_u)}=1\)。

所以这个子树的价值可以换为子树里 \((2-deg_i)\) 的和。

又注意到如果子树的根 \(r\) 满足 \(len_r\leq dis_r\) 那么整个子树都满足这个条件。

所以整个树的答案就是:\(\sum_{i=1}^{n}{[len_i\leq dis_i]\times (2-deg_i)}\)。

然后把这个式子用点分治做即可。

时间复杂度:\(O(n\log n)\)。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 7e4 + 5;

int n, rt;
int ans[kMaxN], f[kMaxN], deg[kMaxN], sz[kMaxN], mx[kMaxN];
bool del[kMaxN];
std::vector<std::pair<int, int>> vec;
std::vector<int> G[kMaxN];

struct BIT {
  int c[kMaxN * 2];

  void upd(int x, int v) {
    x += n + 1;
    for (; x <= 2 * n + 1; x += x & -x) c[x] += v;
  }

  int qry(int x) {
    x += n + 1;
    int ret = 0;
    for (; x; x -= x & -x) ret += c[x];
    return ret;
  }
  int qry(int l, int r) { return qry(r) - qry(l - 1); }
} bit;

void pre_dfs1(int u, int fa) {
  if (G[u].size() == 1) f[u] = 0;
  else f[u] = 1e9;
  deg[u] = G[u].size();
  for (auto v : G[u]) {
    if (v == fa) continue;
    pre_dfs1(v, u);
    f[u] = std::min(f[u], f[v] + 1);
  }
}

void pre_dfs2(int u, int fa) {
  for (auto v : G[u]) {
    if (v == fa) continue;
    f[v] = std::min(f[v], f[u] + 1);
    pre_dfs2(v, u);
  }
}

void getsz(int u, int fa) {
  sz[u] = 1, mx[u] = 0;
  for (auto v : G[u]) {
    if (v == fa || del[v]) continue;
    getsz(v, u);
    sz[u] += sz[v], mx[u] = std::max(mx[u], sz[v]);
  }
}

void getrt(int u, int fa, int tot) {
  mx[u] = std::max(mx[u], tot - sz[u]);
  for (auto v : G[u]) {
    if (v == fa || del[v]) continue;
    getrt(v, u, tot);
  }
  if (mx[u] < mx[rt]) rt = u;
}

void dfs2(int u, int fa, int dis) {
  ans[u] += bit.qry(-n, dis);
  vec.emplace_back(f[u] - dis, 2 - deg[u]);
  for (auto v : G[u]) {
    if (v == fa || del[v]) continue;
    dfs2(v, u, dis + 1);
  }
}

void dfs1(int u, int fa) {
  bit.upd(f[u], 2 - deg[u]);
  vec = {{f[u], 2 - deg[u]}};
  int lst = 1;
  for (int i = 0; i < G[u].size(); ++i) {
    int v = G[u][i];
    if (v == fa || del[v]) continue;
    dfs2(v, u, 1);
    for (int i = lst; i < vec.size(); ++i) bit.upd(vec[i].first, vec[i].second);
    lst = vec.size();
  }
  for (auto [x, v] : vec) bit.upd(x, -v);
  vec.clear(), lst = 0;
  for (int i = (int)G[u].size() - 1; ~i; --i) {
    int v = G[u][i];
    if (v == fa || del[v]) continue;
    dfs2(v, u, 1);
    for (int i = lst; i < vec.size(); ++i) bit.upd(vec[i].first, vec[i].second);
    lst = vec.size();
  }
  ans[u] += bit.qry(-n, 0);
  for (auto [x, v] : vec) bit.upd(x, -v);
  vec.clear();

  del[u] = 1;
  for (auto v : G[u]) {
    if (v == fa || del[v]) continue;
    rt = 0, getsz(v, u), getrt(v, u, sz[v]), dfs1(rt, 0);
  }
}

void dickdreamer() {
  std::cin >> n;
  for (int i = 1; i < n; ++i) {
    int u, v;
    std::cin >> u >> v;
    G[u].emplace_back(v), G[v].emplace_back(u);
  }
  pre_dfs1(1, 0), pre_dfs2(1, 0);
  mx[0] = 1e9, getsz(1, 0), getrt(1, 0, n), dfs1(rt, 0);
  for (int i = 1; i <= n; ++i) {
    std::cout << (deg[i] != 1 ? ans[i] : 1) << '\n';
  }
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  // std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:USACO18JAN,结点,int,题解,len,Large,kMaxN,贝茜,dis
From: https://www.cnblogs.com/Scarab/p/18013097

相关文章

  • [AGC062B] Split and Insert 题解
    题目链接点击打开链接题目解法咋神仙区间\(dp\)题永远想不到区间\(dp\)???首先把操作顺序反转那么现在的问题就是:每次可以选出一个子序列放到序列末尾,使序列升序的最小代价这个问题看着也是毫无头绪我尝试去找些规律,当然也没找到考虑精细刻画操作过程:最终的序列是升序的,最......
  • P8670 [蓝桥杯 2018 国 B] 矩阵求和 题解
    题目传送门前置知识欧拉函数解法欧拉反演,简单地推下式子即可。\(\begin{aligned}\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\gcd(i,j)^{2}&=\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{d=1}^{n}d^{2}[\gcd(i,j)=d]\\&=\sum\limits_{i=1}^{n}\sum......
  • Ucup2 -19题解
    Ucup2-19题解:​ 这场的题还是挺有意思的,之前回家后因为过年的准备+美赛摆了挺久没训练,现在开始复健,顺便复活一下死去已久的博客。​ 水题就不赘述了,这次主要说说几道比较难的但思路很有趣的题目,顺序就按难度排吧。G.LCACountingProblem-G-Codeforces题意:给定一颗无向......
  • AtCoder ABC 263 D 题解
    AtCoderABC263D题解前言本蒟蒻的第一篇题解,大佬勿喷QwQ传送门们洛谷传送门AtCoder传送门正文设有\(x\)使得\(x\leqk\)时,令\(f(k)\)为对\(A'\)进行运算后\(A'=(A_1,A_2,\ldots,A_k)\)的最小和。同理,对于\(y\)使得\(y\leqk\)时,令\(g(k)\)为对\(A......
  • 新年欢乐赛题解
    cyh巨佬举办的比赛。比赛页面赛后补题官方题解赛时没时间写题,赛后补一下。T1:默认排名第一,对于每次输入,若输入的成绩更优,则将排名降低。这里更劣的成绩没用,因为默认初始排名第一。T2:At上的一道原题。考虑DP求解。\(dp_{i,0/1}\)分别表示到第\(i\)张翻和不翻的总......
  • P9170 [省选联考 2023] 填数游戏 题解
    Description众所周知,Alice和Bob是一对好朋友。今天,他们约好一起玩游戏。一开始,他们各自有一张空白的纸条。接下来,他们会在纸条上依次写\(n\)个\([1,m]\)范围内的正整数。等Alice写完,Bob在看到Alice写的纸条之后开始写他的纸条。Alice需要保证她写下的第\(i\)个......
  • P9478 [NOI2023] 方格染色题解
    题解对于行操作,列操作和对角线操作,实际上仅仅只是在对若干个矩形求面积并而已,这是裸的扫描线题,套用模板即可,此时注意到对角线操作实际上是\(O(n)\)量级的矩阵面积并,因此复杂度是\(O(n\logq+q\logq)\)的量级,只能获得95pts。显然,面积并具有交换性,我们先做\(O(q\logq)\)......
  • uoj839 龙门题字 题解
    题目链接点击打开链接题目解法呜呜呜,我考场上只会\(60\),不会优化,没救了要求字典序最大,不难想到一位一位钦定,那么我们现在的问题是判断\(ans_1,...,ans_i\)是否合法,记\(ok_{i,j}\)表示第\(i\)个修改在第\(j\)位是否可行(即\(x_{i,j}\geans_j\)),同时记\(cnt_i\)为第......
  • 2024大试牛刀5题解
    鼠鼠我鸭没学过前缀和的自己去补一下,这里不过多赘述(其实是我不想写)以第二组数据为例:类型0100体重2565先计算出不使用魔法时鸭鸭的重量,当作基础值\(ori=5\)。然后来看看对一段区间使用魔法会造成什么效果:类型0100体重2565变化a+2-5......
  • ABC338G题解
    也许是一个简单一点的做法?假如我们要求一个表达式的值,我们求的顺序显然是,按照加号划分为若干段,段内只有数字和乘号,计算出段内结果后全部加起来。称一个只有数字和乘号的表达式是基本表达式,我们将每个表达式的贡献拆分为若干个基本表达式之和,那么我们就可以枚举每个基本表达式,算......