Блог пользователя Recos

Автор Recos, история, 9 лет назад, По-русски

Доброго времени суток!

- Задача называется Сжатие координат.

Как написать Дерево отрезков, которое умеет считать сумму на интервале, но требует для хранения память, пропорциональную размеру изначального массива.И чтобы оно потребляло память, примерно пропорциональную количеству операций обновления. buildSegmentTree принимает параметр n — длину массива, но не сам массив. Считается, что изначально весь массив заполнен нулями.

  • Ссылка на задачу

    Заранее Спасибо!!!

  • Проголосовать: нравится
  • -8
  • Проголосовать: не нравится

»
9 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Как-то давно писал эту задачку: просто не нужно хранить каждый элемент дерева отрезков, достаточно хранить только изменённые, а про остальные всё известно — они одинаковые. такое работает если размер массива большой а операций на изменение мало, и массив изначально из одинаковых элементов

с памятью O(N) не получится сделать

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Интересно было бы на код посмотреть, если можно.

    • »
      »
      »
      9 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Я так понимаю вы храните дерево в виде обычного массива. создайте структуру node, в которой объявите значение и указатели на левого и правого потомка, а при обращении к ним создавайте их

»
9 лет назад, # |
  Проголосовать: нравится +5 Проголосовать: не нравится

Неявное Дерево Отрезков

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Можно подробнее о Неявном Дерево отрезков

    • »
      »
      »
      9 лет назад, # ^ |
      Rev. 2   Проголосовать: нравится +5 Проголосовать: не нравится

      В обычном дереве отрезке потомками вершины V будут V+V и V+V+1.
      Но в неявном ДО изначально у нас нету потомков, мы их дальше по ходу программы будем создавать. Для каждой вершины будем хранить номер его левого и правого потомка(0 если не существует). Если во время обновления потомка не существует то создаем его, а если в функции get не существует потомка то просто не будем туда спускатся(так как там мы все равно ничего не найдем).
      Реализация update

      int cnt = 1;//количество созданных вершин
      void upd(int id, long long x, int v=1, int l=0, int r=INF){
          if(l>r) return;
          if(l == r){
              t[v] = x;
              return;
          }
          int mid = (l+r) / 2;
          if(id <= mid){
              if(!L[v]) L[v] = ++cnt; //если не существует левого сына, создаем
              upd(id, x, L[v], l, mid);
          }
          else{
              if(!R[v]) R[v] = ++cnt;
              upd(id, x, R[v], mid+1, r);
          }
          t[v] = t[L[v]] + t[R[v]];
      }
      

      Реализация get(в этом случае сумма)

      long long get(int l, int r, int v=1, int tl=0, int tr=INF){
          if(!v || l>r || tl>tr || tl > r || tr < l) return 0;
          if(l <= tl && tr <= r) return t[v];
          int mid = (tl+tr) / 2;
          return get(l, r, L[v], tl, mid) + get(l, r, R[v], mid+1, tr);
      }
      

      Каждая функция создает максимум LogN дополнительной памяти.

»
9 лет назад, # |
  Проголосовать: нравится -8 Проголосовать: не нравится

"дерево который"?

  • »
    »
    9 лет назад, # ^ |
      Проголосовать: нравится +12 Проголосовать: не нравится

    Если заглянуть в профиль автора вопроса, то можно заметить, что русский — не родной для него язык, что может вызывать затруднения, грамматические ошибки и прочее при изъяснении.

    Вообще, об ошибках и опечатках лучше писать в ЛС — таким образом вы не засоряете дискуссию.