首页 > 其他分享 >P5773 [JSOI2016] 轻重路径 题解

P5773 [JSOI2016] 轻重路径 题解

时间:2024-12-16 22:42:56浏览次数:3  
标签:rt sz JSOI2016 int 题解 P5773 wson kMaxN std

Description

在二叉树上,不断删除叶子,你要维护其重链剖分后重儿子编号和。如果两个孩子大小相同,在一开始连向左儿子,后面保持修改前的连接。

\(n\leq 2\times 10^5\)。

Solution

考虑把一个叶子 \(x\) 删掉会对改变哪些点的重儿子。

首先改变的点 \(y\) 一定在 \(x\) 到根的链上,同时要求 \(sz_y\leq\frac{sz_{fa_y}}{2}\)。

那么不妨设当前从上到下修改到 \(rt\),则 \(sz_y\leq\frac{sz_{fa_y}}{2}\leq\frac{sz_{rt}}{2}\),可以通过倍增找到链上最上面的满足 \(sz_y\leq\frac{sz_{rt}}{2}\) 的 \(y\),暴力判断 \(y\) 能否被修改然后将 \(rt\) 设为 \(y\) 继续找即可。

由于有 \(O(n\log^2n)\) 次查询子树大小的操作,直接树状数组为 \(O(n\log^3n)\),用分块 \(O(1)\) 求区间和即可做到 \(O(n\log^2n+n\sqrt n)\)。

时间复杂度:\(O(n\log^3n)/O(n\log^2n+n\sqrt n)\)。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 2e5 + 5;

int n, m, lg;
int64_t sum;
int a[kMaxN], p[kMaxN][19], dfn[kMaxN], sz[kMaxN], wson[kMaxN];
int L[kMaxN], R[kMaxN];
std::vector<int> G[kMaxN];

struct BIT {
  int c[kMaxN];

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

int getsz(int x) {
  if (!x) return 0;
  else return bit.qry(dfn[x], dfn[x] + sz[x] - 1);
}

void dfs(int u, int fa) {
  static int cnt = 0;
  dfn[u] = ++cnt, sz[u] = 1, p[u][0] = fa;
  for (int i = 1; i <= lg; ++i) p[u][i] = p[p[u][i - 1]][i - 1];
  for (auto v : G[u]) {
    if (v == fa) continue;
    dfs(v, u);
    sz[u] += sz[v];
    if (sz[v] > sz[wson[u]]) wson[u] = v;
  }
  sum += wson[u];
}

void update(int x) {
  bit.upd(dfn[x], -1);
  int rt = 1;
  for (; rt != x;) {
    int y = x, now = getsz(rt);
    for (int i = lg; ~i; --i)
      if (p[y][i] && getsz(p[y][i]) <= getsz(rt) / 2)
        y = p[y][i];
    int fa = p[y][0];
    if (y == wson[fa]) {
      int z = L[fa] + R[fa] - y;
      if (getsz(z) > getsz(y)) sum -= y, wson[fa] = z, sum += z;
    }
    rt = y;
  }
  if (x == wson[p[x][0]]) sum -= x;
}

void dickdreamer() {
  std::cin >> n;
  lg = std::__lg(n);
  for (int i = 1; i <= n; ++i) {
    std::cin >> L[i] >> R[i];
    if (L[i]) G[i].emplace_back(L[i]);
    if (R[i]) G[i].emplace_back(R[i]);
  }
  dfs(1, 0);
  std::cin >> m;
  for (int i = 1; i <= n; ++i) bit.upd(i, 1);
  std::cout << sum << '\n';
  for (int i = 1; i <= m; ++i) {
    int x;
    std::cin >> x;
    update(x);
    std::cout << sum << '\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;
}

标签:rt,sz,JSOI2016,int,题解,P5773,wson,kMaxN,std
From: https://www.cnblogs.com/Scarab/p/18611260

相关文章

  • YbtOj题解索引
    不想写作业,水篇博客图论:并查集(已完结)最小生成树(已完结)强连通分量(已完结)最短路径(已完结)数据结构:堆(已完结)RMQ问题(未完结)树状数组(未完结)动态规划:数位DP(未完结)......
  • 题解 - 最小的Y
    题目描述程序设计与数学密切相关,所以兴趣小组的辅导老师经常拿一些有趣的数学题来让大家思考。一次课上,辅导老师又拿出了一个有趣的数学问题,题目是这样的:给你两个正整数x和z,求最小的整数y,使得x×y以后再除以z的余数为0。比如x=3,z=6,求最小的y。题目一出,马上有同学说:最小......
  • 2021ICPC EC final B. Beautiful String题解
    今天跟队友vp21年ECfinal,最后可惜计算几何没开出来,以及J题时间不够没做出来,主要就是B做太麻烦了,导致花了太多时间。但是作为串串人,还是非常喜欢字符串题,这里写一下我们的B题做法。题意定义一个好串是能将字符串分为6个部分\(s_1+s_2+s_3+s_4+s_5+s_6\)并且满足\(s_1=s_2=s_5,......
  • NOIP2024 题解
    考场上一直都不知道在想什么,心态也很不好,结果B一直不会,最后会了C还没写完。感觉这个赛季对我来说就已经结束了吧/hsh/wn本来是想退役的,但是学文化课对我来说太痛苦了,而且我还是比较热爱OI的,所以就再试着走一走吧。P11361[NOIP2024]编辑字符串发现限制就是将\(s\)......
  • 洛谷P7911 [CSP-J 2021] 网络连接题解
    普通的模拟题,数据很小,基本排除超时超空间的可能上代码:#include<bits/stdc++.h>#defineLLlonglongusingnamespacestd;vector<pair<int,string>>sv;//用于存储Server,sv[i].first代表Server编号,sv[i].second代表Server地址intturn(stringstr){//string转int if(str.......
  • STM32F407ZGT6-UCOSIII笔记2:UCOSIII任务创建实验-Printf 函数卡住 UCOSIII 系统问题解
    今日简单编写熟悉一下UCOSIII系统的任务创建代码,理解一下OS系统:并发现以及解决了Printf函数卡住UCOSIII系统问题解决文章提供测试代码讲解、完整工程下载、测试效果图目录文件结构解释:任务函数文件:目前各个文件任务:#include"main.h"#include"ComTask.h"#includ......
  • [SCOI2016] 幸运数字 题解
    \(xor\)最大值想到线性基,路径想到\(lca\)和树链剖分,由于没有修改用\(lca\)就可以。先用处理\(fa\)数组的方式处理倍增线性基(自然是得用线性基合并的),在求\(lca\)时把所有线性基全部合到一块儿就行。考虑到本题实际上核心在于让路径上的线性基数量\(\leO(\logn)\),所以......
  • [题解]AtCoder Beginner Contest 383(ABC383) A~F
    A-aaaadaa按题意模拟即可。点击查看代码#include<bits/stdc++.h>usingnamespacestd;intn;charc1,c2;strings;signedmain(){ cin>>n>>c1>>c2>>s; for(inti:s){ if(i==c1)cout<<c1; elsecout<<c2; } return0;}B-......
  • 题解:(A)[EPXLQ2024 fall round] 风吹起了从前
    (A)[EPXLQ2024fallround]风吹起了从前题意给定\(n\)个字符串\(a_1\)到\(a_n\)。第\(i\)个字符串拥有一个深度值\(r_i\),有一个价值\(v_i\)。再给你\(m\)次询问,每次给出一个字符串\(t\)和深度\(d\),求以\(t\)为前缀且深度值小于\(d\)的字符串价值之和。Soluio......
  • 题解:P11372 「CZOI-R2」加训
    暴力三重循环,枚举学生,障碍和老师,再判断是否合法。时间复杂度:\(\Theta(mxy)\)。但是会TLE。暴力优化用数组\(oier\)来存储二元组\((x,y)\)对应的坐标\(z\)。这样就省去的开三维数组的成本。然后只用枚举学生和老师,再判断维度坐标不同数是否为\(k-1\)个,以及中间有没......