Runtime error khi khởi tạo trong struct

Em đang học segment tree thì lúc đến phần khởi tạo size là power của 2, khi em dùng size = 2*size như bên dưới nộp bài thì bị runtime error. còn Gán luôn sums.assign(2*size, 0)` thì lại accept ạ. Mọi người giải thích giúp em được không ạ, em cảm ơn.

#include <bits/stdc++.h>
#define int long long
using namespace std;
struct segTree {
   int size;
   vector <int> sums;
   inline int getMid (int x, int y) {
      return (x+y)/2;
   }
   void init(int n) {
      size = pow(2,ceil(log2(n)));
      sums.assign(2*size, 0LL);
   }
   void set (int i, int v, int id, int lx, int rx) {
       if (rx - lx == 1) {
           sums[id] = v;
           return;
       }
       int mid = getMid(lx,rx);
       if (i < mid) {
          set(i,v,id*2 + 1,lx,mid);
       } else {
          set(i,v,id*2 + 2,mid,rx);
       }
       sums[id] = sums[id*2+ 1] + sums[id*2+2];
   }
   void set (int i, int v) {
      set (i,v,0,0,size);
   }
   int sum (int l, int r, int id, int lx, int rx) {
       if (l >= rx or r <= lx) {
          return 0;
       }
       if (lx >= l && rx <= r) {
          return sums[id];
       }
       int mid = getMid(lx,rx);
       return sum(l,r,id*2 + 1,lx,mid) + sum(l,r,id*2 + 2,mid,rx);
   }
   int sum (int l, int r) {
       return sum (l,r,0,0,size);
   }
};
signed main () {
    ios_base::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
   int n, m;
   cin >> n >> m;
   segTree st;
  st.init(n);

   for (int i = 0;i < n;i++) {
     int x;
     cin >> x;
     st.set(i,x);
   }
   while(m--) {
    int op;
    cin >> op;
    if (op == 1) {
        int i,v;
        cin >> i >> v;
        st.set(i,v);
    }
    else {
       int l, r;
       cin >> l >> r;
       cout << st.sum(l,r) << '\n';
    }
   }
   return 0;
}

chỉ có thêm cái sum.assign mà đoạn code trên hoạt động thì hơi lạ. có chắc đây là code đầy đủ?

2 Likes

mảng ban đầu chỉ có 0 phần tử làm sao assign size phần tử được :V
xài sum.resize(size, 0); nha :V

edit: assign có tự động resize mảng :V

4 Likes

Em đăng đầy đủ rồi ạ :v, em nhận ra lỗi rồi ạ, cảm ơn nhiều ạ

Do ở dưới nếu mà 2*size thì sẽ bị out of bound lúc em tìm sum range

edit: assign cũng có resize luôn :V

vector có sẵn biến size ở trỏng rồi, ko cần thêm biến size làm gì. Để tạo mảng mới từ mảng có sẵn có n phần tử mới thì viết thế này:

sums.resize(2 * pow(2, ceil(log2(n))), 0);
// truy cập biến size thông qua `sum.size()`, ko cần `int size;` nữa

C++ struct có hàm khởi tạo riêng gọi là constructor nha:

struct SegTree { // tên struct nên viết hoa chữ đầu :V 
  vector<int> sums;
  SegTree(int n) {
    sums.resize(2 * pow(2, ceil(log2(n)))); // nếu khởi tạo giá trị 0 thì ko cần viết vì resize mặc định phần tử mới có giá trị mặc định của int là 0
  }
};

rồi ở dưới viết là

SegTree st(n);

vector nó cũng có hàm khởi tạo sẵn, nhưng vào thân hàm constructor thì ko gọi được nữa, phải gọi trước thân hàm như thế này:

struct SegTree {
  vector<int> sums;
  SegTree(int n) : sums(2 * pow(2, ceil(log2(n)))) { /* thân hàm rỗng */ }
};

và cuối cùng là constructor mà chỉ có 1 tham số thì nên có thêm explicit đằng trước để tránh vụ C++ cast ngầm định từ int sang SegTree:

  explicit SegTree(int n) : sums(2 * pow(2, ceil(log2(n)))) {}
4 Likes

Chi tiết ghê, em cảm ơn ạ với lại em có thắc mắc:

struct SegTree {
  vector<int> sums;
  SegTree(int n) : sums(2 * pow(2, ceil(log2(n)))) { /* thân hàm rỗng */ }
};

Vector hàm khởi tạo sẵn là gì mà không được viết trong constructor vậy ạ với lại em không hiểu cấu trúc mà anh viết ở trên này constructor(int n): (vector(size)) cho lắm ạ

nó gọi là “member initializer listhttps://en.cppreference.com/w/cpp/language/constructor
syntax là : rồi theo sau là khởi tạo phần tử. Trong C++ biến có thể khởi tạo trong dấu () hay {} (C++11), mà khởi tạo bằng : ko cho phép viết n = ... nên mới viết n(...) như thế kia

struct S {
  string s;
  int n;
  int m;
  int i;
  vector<int> a;
  vector<double> b;
  vector<int> c;

  // khởi tạo s = "Hello", n = 101, m = 102, i = 0, a = {1,1,1,1,1}, b = {1.1,2.2}, c = {111}
  // với int thì () {} tương tự
  // với vector thì:
  // - vector<T>(n) khởi tạo mảng có n phần tử có gtrị mặc định là T()
  // - vector<int>(n, val) khởi tạo mảng có n phần tử có gtrị là val
  // - vector<int>{n} khởi tạo mảng có 1 phần tử là n
  // - vector<int>{n, val} khởi tạo mảng có 2 phần tử là n và val {n, val}
  // - vector<int>{a, b, c, d, e} khởi tạo mảng có 5 phần tử là a,b,c,d,e
  S() : s{"Hello"}, n{101}, m(102), i{}, a(5, 1), b{1.1, 2.2}, c{111} {} 
};

sở dĩ phải xài member initializer list là vì vô trong thân hàm khởi tạo thì các member của struct/class đã được khởi tạo mặc định hết rồi, ko gọi hàm khởi tạo được nữa :V

struct S {
  string s;
  int n;
  vector<int> a;
  
  S() /* ko khởi tạo trước bằng : ở đây */ {
    // xuống đây "khởi tạo" thì s, a đã được khởi tạo theo default ctor rồi
    // trừ n ra do các primative types ra ko được khởi tạo (chứa giá trị rác)
    cout << "s = " << s << "\n"; // string mặc định là chuỗi rỗng ""
    cout << "n = " << n << "\n"; // int ko được khởi tạo, giá trị là ko xác định, ngẫu nhiên
    cout << "a.size() = " << a.size() << "\n"; // vector mặc định là mảng rỗng size = 0 {}
  }
};

ngoài ra trong kế thừa/đa hình muốn khởi tạo base class thì phải xài member initializer list ko có cách nào khác :V

C++ hiện đại giờ lại có thể gán giá trị mặc định ngay tại chỗ luôn:

struct S {
  string s = "hi";
  int n = 1;
  int m{};
  vector<int> a;
  
  S() /* ko khởi tạo bằng : ở đây */ {
    cout << "s = " << s << "\n"; // in ra hi vì đã gán mặc định cho s ở trên
    cout << "n = " << n << "\n"; // in ra 1 vì đã có gán mặc định cho n là 1 ở trên
    cout << "m = " << m << "\n"; // in ra 0 vì đã có gán mặc định cho m là {} hay default ctor của int là 0
    cout << "a.size() = " << a.size() << "\n"; // vector mặc định là mảng rỗng size = 0 {}
  }
};

khá nhiều lựa chọn dẫn tới code ko ai giống ai cả :dizzy_face:

3 Likes
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?