首页 > 其他分享 >CF1192B Dynamic Diameter 题解

CF1192B Dynamic Diameter 题解

时间:2024-06-08 09:44:09浏览次数:15  
标签:Diameter ln int 题解 Dynamic fa un text ct

思路

静态 \(\text{top tree}\) 板子题。

定义

我们使用簇来表示树上的一个连通块。

可以按照如下方式定义一个簇:

  1. 一个簇可以表示为三元组 \((u,v,E)\),其中 \(u,v\) 为树的节点,称为簇的界点,\(E\) 为一个边的集合,表示该簇包含的边,路径 \((u,v)\) 称作簇路径。
  2. \(u,v\) 分别为上界点与下界点,上界点是一个簇内深度最小的点,下界点则是除去上界点外的界点。
  3. 界点可以通俗的理解为簇与簇的分界点。
  4. 对于树的一条边 \((u,v)\),\((u,v,{(u,v)})\) 是一个簇。
  5. 对于簇 \((u,v,E_1)\) 与簇 \((v,w,E_2)\) 且 \(E_1\cap E_2=\varnothing\),那么 \((u,w,E_1\cup E_2)\) 也是一个簇,这个操作称为 \(\text{compress}\)。
  6. 对于簇 \((x,v,E_1)\) 与簇 \((x,w,E_2)\) 且 \(E_1\cap E_2=\varnothing\),那么 \((x,w,E_1\cup E_2)\) (或者 \((x,v,E_1\cup E_2)\))也是一个簇,这个操作称为 \(\text{rake}\)。

经典图:

一个感性理解是 \(\text{rake}\) 将簇与簇融合,\(\text{compress}\) 将簇与簇拼接。

这两个操作可以帮助我们将整棵树合并为一个簇。

  • 对于一度点,进行 \(\text{rake}\)
  • 对于二度点,进行 \(\text{compress}\)。

收缩过程中,簇的合并结构形成了一个树,我们把这个树称为 \(\text{top tree}\)。

现在,这样一个 \(\text{top tree}\) 它的树高有可能是 \(O(n)\) 的。

更优的树

考虑构造一个树高更小的 \(\text{top tree}\)。

容易想到的是全局平衡二叉树。

全局平衡二叉树提供了一个分治方案使整棵树的全局平衡二叉树树高为 \(O(\log n)\)。

我们同样可以把这个分治方案放在 \(\text{top tree}\) 上。

具体的,将树进行重链剖分。

然后对于轻儿子,先把它们 \(\text{rake}\) 起来。

再对重链分治 \(\text{compress}\),找分割点时,我们按每个点合并完轻儿子后的簇的大小带权找到中点。

这样就可以建出一颗树高为 \(O(\log n)\) 的 \(\text{top tree}\) 了。

关于这道题

建出 \(\text{top tree}\) 后有什么用呢。

我们想线段树一样的操作它

对于动态直径。

我们把每一个簇,维护三个值。

簇内部的最长距离及到两个界点的最长距离。

合并时我们对两种操作分类讨论拼接起来即可。

可以发现,维护直径的方式与线段树维护最大子段和的方式是比较类似的。

这种维护方法就可以支持一些简单的修改,比如此题的修改边权。

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

Code

/*
  ! 如果没有天赋,那就一直重复
  ! Created: 2024/06/05 19:58:38
*/
#include <bits/stdc++.h>
using namespace std;

#define int long long
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)

const int N = 2e5 + 10;

int n, q, w, ct, last, head[N];
int sz[N], sn[N], fa[N], rt[N], dep[N];
struct Node {
  int u, v, w;
} d[N];
struct edge {
  int to, nxt;
} e[N << 1];
struct node {
  enum { UNIT, RAKE, COMP } type;
  int u, v, sz, ls, rs, fa, ln, mi, un, vn;
} t[N << 1];

inline void add(int x, int y) {
  e[++ct] = {y, head[x]}, head[x] = ct;
  e[++ct] = {x, head[y]}, head[y] = ct;
}
inline void dfs(int now, int fa) {
  sz[now] = 1, dep[now] = dep[fa] + 1;
  for (int i = head[now]; i; i = e[i].nxt) {
    int x = e[i].to;
    if (x == fa) continue;
    dfs(x, now);
    t[x] = {node::UNIT, now, x, 1};
    sz[now] += sz[x];
    if (sz[x] > sz[sn[now]]) sn[now] = x;
  }
}
inline void pup(int p) {
  int x = t[p].ls, y = t[p].rs;
  if (t[p].type == node::RAKE) {
    t[p].ln = t[x].ln;
    t[p].mi = max({t[x].mi, t[y].mi, t[x].un + t[y].un});
    t[p].un = max(t[x].un, t[y].un);
    t[p].vn = max(t[x].vn, t[x].ln + t[y].un);
  } else if (t[p].type == node::COMP) {
    t[p].ln = t[x].ln + t[y].ln;
    t[p].mi = max({t[x].mi, t[y].mi, t[x].vn + t[y].un});
    t[p].un = max(t[x].un, t[x].ln + t[y].un);
    t[p].vn = max(t[y].vn, t[y].ln + t[x].vn);
  }
}
inline auto rake(int x, int y) {
  assert(t[x].u == t[y].u);
  return t[++ct] = {node::RAKE, t[x].u, t[x].v, t[x].sz + t[y].sz, x, y}, t[x].fa = t[y].fa = ct, pup(ct), ct;
}
inline auto comp(int x, int y) {
  assert(t[x].v == t[y].u);
  return t[++ct] = {node::COMP, t[x].u, t[y].v, t[x].sz + t[y].sz, x, y}, t[x].fa = t[y].fa = ct, pup(ct), ct;
}
template<typename T, typename Func>
inline int build(T l, T r, Func f) {
  if (r == l) return 0;
  if (r == l + 1) return *l;
  int all = 0, sum = 0;
  for (auto it = l; it != r; it++) all += t[*it].sz;
  T mid = l + 1;
  for (auto it = l; it != r; it++) {
    sum += t[*it].sz;
    if (sum <= all / 2) mid = it + 1; else break;
  }
  return f(build(l, mid, f), build(mid, r, f));
}
inline void sol(int now, int ff, bool f) {
  fa[now] = ff;
  if (sn[now]) sol(sn[now], now, false);
  for (int i = head[now]; i; i = e[i].nxt)
    if (e[i].to != sn[now] && e[i].to != fa[now]) sol(e[i].to, now, true);
  if (f) {
    vector<int> s1;
    if (ff) s1.push_back(now);
    for (int i = sn[now]; i; i = sn[i]) {
      vector<int> s2{i};
      for (int j = head[fa[i]]; j; j = e[j].nxt)
        if (e[j].to != i && e[j].to != fa[fa[i]]) s2.push_back(rt[e[j].to]);
      s1.push_back(build(s2.begin(), s2.end(), rake));
    }
    rt[now] = build(s1.begin(), s1.end(), comp);
  }
}
inline void upd(int x, int w) {
  t[x].un = t[x].vn = t[x].mi = t[x].ln = w;
  while (t[x].fa) {
    pup(t[x].fa), x = t[x].fa;
  }
}

signed main() {
  ios::sync_with_stdio(0), cin.tie(0);
  cin >> n >> q >> w;
  fro(i, 1, n - 1) {
    cin >> d[i].u >> d[i].v >> d[i].w;
    add(d[i].u, d[i].v);
  }
  ct = n;
  dfs(1, 0);
  sol(1, 0, 1);
  fro(i, 1, n - 1) {
    if (dep[d[i].u] > dep[d[i].v])
      swap(d[i].u, d[i].v);
    upd(d[i].v, d[i].w);
  }
  fro(i, 1, q) {
    int x, y;
    cin >> x >> y;
    x = (x + last) % (n - 1) + 1;
    y = (y + last) % (w);
    d[x].w = y;
    upd(d[x].v, d[x].w);
    cout << (last = t[rt[1]].mi) << "\n";
  }
  return 0;
}

标签:Diameter,ln,int,题解,Dynamic,fa,un,text,ct
From: https://www.cnblogs.com/JiaY19/p/18238313

相关文章

  • 无限之环 题解
    五星压行大师\(lyh\)表示:这是难得能让他的代码长度打破百行大关的题目(182行)。首先,根据科技与狠活,本题可以黑白染色。源点联向白格,黑格连向汇点。发现每个格子都可以连向四个方向,所以可以建立四个点,代表水管连到了上下左右四个方向。设四元组\((x,y,z,p)\)表示水管初始状态......
  • 开车旅行|倍增优化dp+双端列表/set|题解
    题面:题面链接这题的思路值得借鉴,也是我做的第一道倍增优化dp题目.比较好的是题目的意思较为清晰,所以不再赘述.解析:这里我们可以非常直接的想到暴力模拟,因为第一眼看上去前七个点的数据范围是支持我们进行一个简单的预处理得到对应人在对应位置的决策的.(排序O(n×sqrt(......
  • [ABC107D] Median of Medians 题解
    题目大意:一个长度为$M$的序列的中位数为这个序列从小到大排序后第$\lfloor\fracM2\rfloor+1$个数,将这个序列的所有子段的中位数放入一个序列中,求这个序列的中位数。设一个序列$a$的中位数为$x$,那么$a$中至少会有一半的数大于等于$x$,并且$x$是$a$中满足这个条件......
  • プログラミングコンテストチャレンジブック 题解
    题目大意:从$n$根木棒里选出六根拼成两个合法的三角形,使这两个三角形的周长和最大。考虑贪心,证明在后面。首先我们要知道一个三角形基本定理:较短两边长度之和大于最长边。那我们就根据这个定理先去寻找最大三角形的最长边。先排序,然后循环枚举,对于每个$a_i$,可以寻找到的最大......
  • [COCI2020-2021#2] Sjekira 题解
    题目大意:把一棵树完全分解,每次分解一条边的代价是这条边连接的两个连通块的最大点权之和,求最小代价。逆序模拟,既然题目要求将树完全分解,那我们就每次逆序连接当前权值最小的两个点,也就是贪心的思路。尝试将贪心的值写成一个表达式:$$\sum_{i=1}^na_i+\sum_{(u,v)\inE}\max(a......
  • [ABC036D] 塗り絵 题解
    题意题面讲挺清楚的就不简化了。思路树上求方案数,很明显是树上dp。设$dp_{i,0/1}$表示第$i$个点涂成白/黑色的方案数。当前结点如果为白色,那么它的子节点涂成什么颜色都没关系,根据分步乘法原理,将它子结点涂成白/黑色的方案数之和乘起来即可;当前结点如果为黑色,那么它的子......
  • [ABC126D] Even Relation 题解
    题意对一棵有$N$个点,$N-1$条边的树进行黑白染色,使得每两个距离为偶数的点颜色都一致。思路首先让我们回顾一下加法的性质:偶$+$偶$=$偶奇$+$奇$=$偶偶$+$奇$=$奇不难看出,距离为偶数的关系是可以传递的,而距离为奇数的关系不行。我们只需要做一遍dfs,对一个......
  • [ABC191E] Come Back Quickly 题解
    题面:给你一个$n$个点$m$条边的有向图,第$i$条边$a_i$,$b_i$,$c_i$,表示一条单向边从$a_i$到$b_i$,长度为$c_i$,可能会有重边和自环。问能否从第$i$号点出发然后回到该点形成一个环?可以则输出最短时间,否则输出$-1$。思路:不难发现本题考查的是最短路。观察题面,发现边数......
  • [ABC126F] XOR Matching 题解
    很好的构造题。题意请构造一个长度为$2^{m+1}$的序列$a$,该序列满足:$\foralli\in[1,2^{m+1}],a_i\in[0,2^m-1]$且每个数都恰好出现两次。对于任意一对$(i,j)$满足$a_i=a_j$,$a_i\oplusa_{i+1}\oplus\cdots\oplusa_{j-1}\oplusa_j=k$。$\oplus$表......
  • 食物链题解
    由题得,所有动物整体关系如上。起初每个动物相互时间没有关系,bb[i]=i。对于x与y:如果它们是同类即x到y的距离为$0$,或者转了几圈,一圈距离为$3$,即模$3$余$0$。如果x捕食y,就是x到y距离模$3$余$1$。对x与y操作时:如果它们没有关系(它们不被之前给出的某......