鱼C论坛

 找回密码
 立即注册
查看: 435|回复: 2

[已解决]唔,一个百思不得其解的 树状树状题目相关的问题

[复制链接]
发表于 2023-6-12 18:19:39 | 显示全部楼层 |阅读模式
60鱼币
A6E1$UMN4C(J6YU}LN%E%P3.png 这里s[l] % x != 0。那后面应该没有用了吧?为什么= nullptr;   后原来对的会变成错的?
加上前 2~Y@VX081N02%I_JTDSUWLM.png
加上后 VOZUS6M`(Y}5YMS$VBYVT_L.png
  1. #include <iostream>
  2. #include <vector>

  3. using namespace std;

  4. const int MAX = 5e5 + 5;

  5. struct Node {
  6.     int l, r;
  7.     long long val;
  8.     Node* left, * right;

  9.     Node(long long val, int l, int r) : val(val), l(l), r(r), left(nullptr), right(nullptr) {}
  10. };

  11. int n, m;
  12. long long s[MAX];
  13. Node* head = nullptr;
  14. Node* f[MAX] = { nullptr };

  15. long long get_val(Node* node) {
  16.     if (node == nullptr)
  17.         return 0;
  18.     return node->val;
  19. }

  20. //查询l到r的和
  21. long long query(Node* node, int l, int r) {
  22.     if (node == nullptr)
  23.         return 0;
  24.     if (l == node->l && r == node->r)
  25.         return node->val;

  26.     int mid = node->l + (node->r - node->l >> 1);
  27.     if (r <= mid)
  28.         return query(node->left, l, r);
  29.     else if (mid < l)
  30.         return query(node->right, l, r);
  31.     else
  32.         return query(node->left, l, mid) + query(node->right, mid + 1, r);
  33. }

  34. //修改v处的值为x
  35. void modify(Node*& node, int l, int r, int v, long long x) {
  36.     if (node == nullptr)
  37.         node = new Node(0, l, r);
  38.     if (node->l == node->r) {
  39.         node->val = x;
  40.     }
  41.     else {
  42.         int mid = node->l + (node->r - node->l >> 1);
  43.         if (v > mid)
  44.             modify(node->right, mid + 1, r, v, x);
  45.         else
  46.             modify(node->left, l, mid, v, x);

  47.         node->val = get_val(node->left) + get_val(node->right);
  48.     }
  49. }

  50. //根据s数组构建一颗树
  51. void create(Node*& node, int l, int r) {
  52.     if (node == nullptr) {
  53.         node = new Node(0, l, r);
  54.     }
  55.     if (l == r) {
  56.         node->val = s[l];
  57.     }
  58.     else {
  59.         int mid = node->l + (node->r - node->l >> 1);
  60.         create(node->left, l, mid);
  61.         create(node->right, mid + 1, r);

  62.         node->val = get_val(node->left) + get_val(node->right);
  63.     }
  64. }

  65. //遍历l~r中的数,将可以除的除了,不能除的删除了
  66. void update(Node*& node, int l, int r, int x) {
  67.     if (node == nullptr) return;

  68.     if (l == r) {
  69.         if (s[l] % x == 0) {
  70.             s[l] /= x;
  71.             modify(head, 1, n, l, s[l]);
  72.         }
  73.         else {
  74.             node = nullptr; //这里不加,大部分超时,加了,答案错误
  75.         }
  76.     }
  77.     else {
  78.         int mid = node->l + (node->r - node->l >> 1);
  79.         if (r <= mid)
  80.             update(node->left, l, r, x);
  81.         else if (mid < l)
  82.             update(node->right, l, r, x);
  83.         else
  84.             update(node->left, l, mid, x), update(node->right, mid + 1, r, x);

  85.         node->val = get_val(node->left) + get_val(node->right);

  86.         if (node->val == 0) {
  87.             node = nullptr;
  88.         }
  89.     }
  90. }

  91. int main() {
  92.     ios_base::sync_with_stdio(0);   //把cin和scnf分割开,加快速度
  93.     cin.tie(0); //解除cin与cout的绑定

  94.     cin >> n >> m;

  95.     for (int i = 1; i <= n; i++) {
  96.         cin >> s[i];
  97.         for (int j = 1; j * j <= s[i]; j++) {
  98.             if (s[i] % j == 0) {
  99.                 modify(f[j], 1, n, i, 1);
  100.                 if (j * j != s[i])
  101.                     modify(f[s[i] / j], 1, n, i, 1);
  102.             }
  103.         }
  104.     }

  105.     create(head, 1, n);

  106.     for (int i = 0; i < m; i++) {
  107.         int num, l, r, x;
  108.         cin >> num >> l >> r;
  109.         if (num == 1) {
  110.             cin >> x;
  111.             if (x == 1) continue;
  112.             update(f[x], l, r, x);
  113.         }
  114.         else {
  115.             cout << query(head, l, r) << '\n';
  116.         }
  117.     }

  118.     return 0;
  119. }
复制代码
最佳答案
2023-6-12 18:19:40
s[l] % x != 0表示该位置的数不能整除x,所以后续的查询和修改都不会用到这个节点了。

但是如果直接node = nullptr删除这个节点,之前通过这个节点存储的信息也会丢失。

举个例子:
原数组:1 2 3 4
构建的线段树:
  1. 1-4 (1+2+3+4=10)
  2. / \
  3. 1-2 (1+2=3) 3-4 (3+4=7)
复制代码


现在有修改操作:2-3 3 (把区间2-3的数除以3)
线段树变成:
  1. 1-4 (1+1+1+4=7)
  2. / \
  3. 1-2 (1+1=2) 3-4 (3+4=7)
复制代码


此时再有查询操作1-4,应该返回7。

而如果直接删除节点3-4,则:

  1. 1-4
  2. /
  3. 1-2 (1+1=2)
复制代码


则查询1-4会返回2,与预期不符。

所以,采用if检查判断是否需要删除节点,如果需要删除再设置为nullptr的做法是正确的。既避免了直接删除节点导致信息丢失的情况,也删除了不再需要的节点。

希望通过这个例子能够理解为什么要加if判断,以及不加if判断会产生什么错误。如果还有不清楚的地方,欢迎再提问。

最佳答案

查看完整内容

s[l] % x != 0表示该位置的数不能整除x,所以后续的查询和修改都不会用到这个节点了。 但是如果直接node = nullptr删除这个节点,之前通过这个节点存储的信息也会丢失。 举个例子: 原数组:1 2 3 4 构建的线段树: 现在有修改操作:2-3 3 (把区间2-3的数除以3) 线段树变成: 此时再有查询操作1-4,应该返回7。 而如果直接删除节点3-4,则: 则查询1-4会返回2,与预期不符。 所以,采用if检查判断是否需要删除 ...
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-6-12 18:19:40 | 显示全部楼层    本楼为最佳答案   
s[l] % x != 0表示该位置的数不能整除x,所以后续的查询和修改都不会用到这个节点了。

但是如果直接node = nullptr删除这个节点,之前通过这个节点存储的信息也会丢失。

举个例子:
原数组:1 2 3 4
构建的线段树:
  1. 1-4 (1+2+3+4=10)
  2. / \
  3. 1-2 (1+2=3) 3-4 (3+4=7)
复制代码


现在有修改操作:2-3 3 (把区间2-3的数除以3)
线段树变成:
  1. 1-4 (1+1+1+4=7)
  2. / \
  3. 1-2 (1+1=2) 3-4 (3+4=7)
复制代码


此时再有查询操作1-4,应该返回7。

而如果直接删除节点3-4,则:

  1. 1-4
  2. /
  3. 1-2 (1+1=2)
复制代码


则查询1-4会返回2,与预期不符。

所以,采用if检查判断是否需要删除节点,如果需要删除再设置为nullptr的做法是正确的。既避免了直接删除节点导致信息丢失的情况,也删除了不再需要的节点。

希望通过这个例子能够理解为什么要加if判断,以及不加if判断会产生什么错误。如果还有不清楚的地方,欢迎再提问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

 楼主| 发表于 2023-6-12 21:30:55 | 显示全部楼层
update() 的 if 条件错了,应该是 node->l == node->r
不然修改的区间的长度为 1 的话就直接判断能不能除了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-4-28 08:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表