首页 > 其他分享 >CF1712F Triameter 题解

CF1712F Triameter 题解

时间:2023-08-31 19:22:48浏览次数:33  
标签:std int 题解 CF1712F dep text ans Triameter size

Description

你有一棵有 \(n\) 个点的树,树上的每条边权值都为 \(1\)。现在有 \(q\) 次询问,每次询问一个整数 \(x\),并将叶子结点全部相连上权值为 \(x\) 的边(操作不会保留)。问每次操作后图的直径是多少。图的直径定义为 \(\underset{1\leq u<v\leq n}{\max}d(u,v)\)。

\(3\leq n\leq 10^6,1\leq q\leq 10\)。

Solution

考虑转化一下 \(d(u,v)\)。

设 \(h_i\) 表示 \(i\) 到叶子节点的最短距离,那么 \(d(u,v)\) 就等于 \(\min\left\{\text{dist}(u,v),h_u+h_v+x\right\}\)。

然后枚举一下 \(u\) 和 \(v\) 的 \(\text{LCA}\),设它为 \(k\)。那么 \(d(u,v)=\min\left\{\text{dep}_u+\text{dep}_v-2\times \text{dep}_k,h_u+h_v+x\right\}\)。

如果当前的答案为 \(ans\),\(d(u,v)\) 只有 \(\text{dep}_u+\text{dep}_v-2\times \text{dep}_k>ans\) 且 \(h_u+h_v+x>ans\) 时 \(ans\) 才可被更新。

设 \(M_{i,j}\) 表示 \(i\) 子树里面 \(h_{x}\) 为 \(j\) 的最大的 \(\text{dep}_x\)。

由于 \(i\) 的子树里面不可能 \(d\) 全都大于 \(d_i\),因为一定有 \(0\),并且相邻的两个点 \(d\) 值相差不超过 \(1\),所以 \(0\sim d_i\) 都会在 \(i\) 的子树里面出现,那么 \(M_{i,j}\geq M_{i,j+1}\)。

然后对于 \(k\) 的两个个儿子 \(a\) 和 \(b\),它们子树里如果存在能让 \(ans\) 更新的点对,说明存在 \(i,j\),使得 \(i+j+x>ans\) 且 \(M_{a,i}+M_{b,j}-2\times\text{dep}_k>ans\)。

移项就得出 \(M_{a,i}+M_{b,\max(ans-x-i+1,0)}-2\times \text{dep}_k>ans\)。

容易发现 \(M_{i,j}\) 不为 \(0\) 说明 \(j\) 不超过 \(i\) 这个子树里面的长链长度,所以直接长剖优化即可。

时间复杂度:\(O(nq)\),常数很大。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 1e6 + 5;

int n, ans, x;
int d[kMaxN], dep[kMaxN];
std::vector<int> G[kMaxN], f[kMaxN];

void dfs1(int u, int fa) {
  dep[u] = dep[fa] + 1;
  if (G[u].size() != 1) d[u] = 1e9;
  for (auto v : G[u]) {
    if (v == fa) continue;
    dfs1(v, u);
    d[u] = std::min(d[u], d[v] + 1);
  }
}

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

void merge(int u, int v) {
  for (int i = 0; i < static_cast<int>(f[v].size()); ++i) {
    for (;;) {
      int j = std::max(ans - x - i + 1, 0);
      if (j < static_cast<int>(f[u].size()) && f[v][i] + f[u][j] - 2 * dep[u] > ans) ++ans;
      else break;
    }
  }
  for (int i = 0; i < static_cast<int>(f[v].size()); ++i)
    f[u][i] = std::max(f[u][i], f[v][i]);
}

void dfs3(int u, int fa) {
  int mxid = 0;
  for (auto v : G[u]) {
    if (v == fa) continue;
    dfs3(v, u);
    if (f[v].size() > f[mxid].size()) mxid = v;
  }
  std::swap(f[u], f[mxid]);
  for (auto v : G[u]) {
    if (v == fa || v == mxid) continue;
    merge(u, v);
  }
  for (;;) {
    int i = std::max(ans - x - d[u] + 1, 0);
    if (i < static_cast<int>(f[u].size()) && f[u][i] - dep[u] > ans) ++ans;
    else break;
  }
  if (d[u] == static_cast<int>(f[u].size()))
    f[u].emplace_back(dep[u]);
}

void dickdreamer() {
  std::cin >> n;
  for (int i = 2; i <= n; ++i) {
    int p;
    std::cin >> p;
    G[p].emplace_back(i), G[i].emplace_back(p);
  }
  dfs1(1, 0), dfs2(1, 0);
  int q;
  std::cin >> q;
  for (; q; --q) {
    std::cin >> x;
    for (int i = 1; i <= n; ++i) {
      f[i].clear(), f[i].shrink_to_fit();
    }
    ans = 0;
    dfs3(1, 0);
    std::cout << ans << ' ';
  }
}

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;
}

标签:std,int,题解,CF1712F,dep,text,ans,Triameter,size
From: https://www.cnblogs.com/Scarab/p/17670268.html

相关文章

  • springcloud 跨域问题解决
    问题原因跨域本质是浏览器基于同源策略的一种安全手段同源策略(Sameoriginpolicy),是一种约定,它是浏览器最核心也最基本的安全功能所谓同源(即指在同一个域)具有以下三个相同点协议相同(protocol)主机相同(host)端口相同(port)反之非同源请求,也就是协议、端口、主机其中一项不相同的......
  • MySQL 使用Navicat delete/insert into/update 大量数据表锁死,kill的线程后线程处于ki
      MySQL使用delete/insertinto/update大量数据表锁死,kill的线程后线程处于killed状态问题解决实际生产环境问题描述:使用Navicat备份BigData数据表时不小心点到了取消按钮,导致数据表被锁。  查看MySQL线程队列,找到刚刚执行的SQL看是属于什么状态。showprocessli......
  • 选博士 题解
    FZQOJLuogu前言​ 节假日在家闲来无事,那就水写一篇题解吧。题目描述​ 前面一大堆废话,总结来说就是:​ 求l--R区间的和​ 但是每一个数转换为它本身所有数位的和,重复这个操作,直到这个数⩽9思路​ 我不知道各位神犇们是怎么做的,所以在此分享一下我的思路前缀......
  • 「USACO3.2」Magic Squarest题解
    「USACO3.2」MagicSquarest题解建议优先阅读题目后再看题解:FZQOJluogu-题目大意给定初始二维数组(也即是题中所说的魔板):12348765并提供以下3种操作:\(A\).交换上下两行;\(B\).将最右边的一行移动到最左边;\(C\).顺时针旋转魔板的中央4个数字询问最少多少次......
  • [USACO05DEC] Layout G 题解
    fzqojluogu题意分别给出\(ml\)和\(md\)对,关于n头奶牛位置的关系,求1号到n号奶牛的最大距离是多少每一对ml的关系转化成不等式就是:\(A-B\leC\)相应的,每一对md的关系转化成不等式就是:\(A-B\geqC\)(\(A\),\(B\)是两头奶牛的位置,\(C\)是他们相差的距离)思路看到多元的......
  • CF1864D Matrix Cascade 题解
    首先把式子拆一下,可以知道\(x-i\ge|y-j|\)等价于\(x-y\gei-j\)和\(x+y\gei+j\),注意到每次操作\((i,j)\),影响到的点\((x,y)\)均要满足\(x>i\),那么我们每次就必须要按照从上往下的顺序进行,否则上面的点无法影响到,即从第一行开始操作。又注意到对于\((i,j)\)如果执......
  • CF1864B Swap and Reverse 题解
    注意到交换操作,无法改变下标的奇偶性,因此只能通过考虑翻转操作改变。注意到如果\(i\)是奇数,那么要令\(i+k-1\)为偶数的话\(k\)必须为偶数,若\(i\)是偶数,要令\(i+k-1\)是奇数的话,\(k\)也应为偶数,而\(k\)为奇数的情况翻转了也无法改变奇偶性。因此通过\(k\)的奇偶性......
  • CF1839C Insert Zero and Invert Prefix 题解
    首先考虑无解的情况,很明显\(a_n\)必须为\(0\),否则没有解,因为如果最后一位为\(1\)那么必须有\(n\)这个数存在于\(b\)序列中,而这种情况时不符合题意的。然后考虑如何求解,先考虑一种比较特殊的情况,就是若干个\(1\)后面接着一个\(0\),这里假设\(1\)的数量有\(k\)个,这......
  • P9437 『XYGOI round1』一棵树 题解
    首先这是一道很明显的换根dp。首先注意到要拼接数,所以我们可以先处理出\(num_i=10^{x}\),使得\(10^x>a_i>10^{x-1}\),这样方便我们后面算贡献。我们以这棵树为例子来推状态转移方程。先假设\(dp_u\)表示以\(1\)为根时,从\(u\)的子树的点到\(u\)的权值和。那么\[......
  • CF1862E Kolya and Movie Theatre 题解
    先注意到我们娱乐值损耗的多少只与最后一场电影有关系,所以假设最后一场电影看的下标为\(k\),那么最后就要减去\(d\timesk\)。得出这个性质之后开个小根堆反悔贪心即可,首先\(a_i<0\)的没必要考虑,对于\(a_i>0\)的,如果还没到\(m\)场电影,我们就直接往里塞就可以,如果到了,我们......