logo AlgoBeat OnlineJudge
登录 注册

#214423. 基础倍增练习题 6 / 小 U 的树

内存限制:512 MiB 时间限制:4000 ms 标准输入输出
题目类型:VJudge(洛谷) 评测方式:VJudge
上传者: 匿名

题目描述

给定 个点,点有权,初始时两两均未连边。

你需要支持 次两种操作之一:

  1. 在两个不联通的点间连上一条边;

  2. 求两个给定点构成路径上所有点权的最大子段和(不能为空)。

强制在线。

输入格式

由于输入量较大,本题数据采用程序内随机生成的方式。

第一行三个正整数 ,其中 为六十四位无符号整数。你需要将 重赋值为对其调用 splitmix64 得到的值。随后你需要调用 rnd() 生成每个点的点权,在有符号三十二位整数范围内。

随后你需要生成 次操作。每次操作调用两次 rnd() 的值加一以生成两个随机点,随后若其不联通则执行操作 1,否则执行操作 2。

关于更多细节,见提示说明部分。

上述数据生成方式仅是为了减少输入量大小,标准算法不依赖于该生成方式。

输出格式

对于每次 2 操作,将答案异或给 。在程序的最后,一行输出 即可。

关于更多细节,见提示说明部分。

样例

样例输入 1

3 3 114514

样例输出 1

17246579553375009221

样例输入 2

10 10 114514

样例输出 2

4275621686360879090

样例输入 3

100000 100000 114514

样例输出 3

12109274478506447081

数据范围与提示

对于 的数据,

对于 的数据,

对于 的数据,

对于 的数据,

对于 的数据,

对于 的数据,


以下是部分样板代码。

随机数部分:

uint64_t sd;
uint64_t rnd() {
  sd ^= sd << 13, sd ^= sd >> 7;
  return sd ^= sd << 17;
}
uint64_t splitmix64(uint64_t x) {
  x += 0x9e3779b97f4a7c15;
  x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9;
  x = (x ^ (x >> 27)) * 0x94d049bb133111eb;
  return x ^ (x >> 31);
}

主函数部分:

  cin >> n >> m >> sd, sd = splitmix64(sd);
  for (int i = 1; i <= n; ++i) a[i] = (uint32_t)rnd();
  // 假设 a 为点权数组,注意其类型为 int。
  while (m--) {
    int u = rnd() % n + 1, v = rnd() % n + 1;
    if (is_connected(u, v))
      sd ^= query(u, v);
    else
      unite(u, v);
    // 假设三个函数的功能分别为:判断是否联通;查询最大子段和;连边。
  }
  cout << sd << endl;

如果你 T 了,可以考虑减少瓶颈复杂度的出现次数。