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

Автор Ocean1001, 11 лет назад, По-русски

Дана довольно банальная задача. Дан массив состоящий из N чисел (N<=10^5). Нужно для каждого числа вывести кол-во чисел, которые лежат справа и которые меньше его самого. Помогите пожалуйста как решать подобную задачу.

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

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

Строишь декатово дерево по явному ключу (с поддержкой размера поддеревьев), двигаясь справа на лево. Соответственно сплитишь по текущему ключу и смотришь, сколько элементов в левом дереве.

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

Используешь дерево отрезков. Если числа большие (<= 10 ^ 9), то сжимаешь координаты, потом идешь справа налево, и для каждого числа a[i] берешь сумму от 1 до a[i] — 1, и не забудь обновить дерево update (a[i], 1).

»
11 лет назад, # |
Rev. 4   Проголосовать: нравится -10 Проголосовать: не нравится

в деревьях не силен, к сожалению, но первое что пришло в голову() возможно не работает и не красиво , просьба не ругать, а лучше указать на ошибки а также более хорошее , оптимальное и правильное решение

mass[]:=1..N;

for (i=0 i<N i++)
  { num=mass[i];
    
	for (j=i+1 j<N j++)
            { if(mass[j]<num)  count++ ;
             } 
    
  mass2[i]=count;count=0;
                  

  print mass[i] : mass2[i] /n;

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

    Твое решение имеет сложность О(N^2). Для массива из 10^5 элементов, твое решение будет очень долго работать.

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

Предлагаю такой алгоритм: Идем по массиву с конца одновременно запихивая числа в multiset, до запихивания очередного числа проверяем сколько в multiset'е чисел меньше текущего, запоминаем ответы.

O (n log n).

Вот только не помню как узнать сколько в multiset чисел меньших какого-то за O(log n).

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

    А с помощью multiset за O(log n) узнать нельзя.

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

      Поэтому я и сказал сверху, что можно юзать декартово дерево, а меня почему-то минусят =(

      UPD. А вообще можно любое бинарное дерево поиска использоавать, просто на мой взгляд декартово писать проще всего

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

        Возможно потому, что дерево Фенвика куда проще.

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

          Расскажи, как решать это задачу деревом фенвика?

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

            http://codeforces.net/blog/entry/8256#comment-139517 . только вместо дерева отрезков дерево Фенвика использовать

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

              Ну там идея немного другая.

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

                Я извиняюсь, но можете рассказать немного другую идею?...я только такую знаю....

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

                Нет, идея и там и там абсолютно одинаковая. Только для дерева отрезком или Фенвика надо сжимать координаты (т.е. так как для числа важен только относительный порядок, а не абсолютное значение, то можно их все кинуть в массив, отсортировать и заменить на индекс в массиве). Для декартова дерева это не требуется. Однако, если числа будут заране неизвестны, а поступать в режиме online, то необходимо будет или декартово дерево или явное дерево отрезков в котором поддеревья с нулем элементов выгружаются из памяти.

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

          Да абсолютно всё, что угодно в этой задаче проще, чем декартово дерево.

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

        Расскажи, в какой вселенной декартово дерево — самое простое из бинарных деревьев?

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

Эта задача аналогична подсчету числа инверсий в массиве, только здесь мы считаем инверсии для каждого элемента, поэтому наравне с использованием различных деревьев можно использовать модификацию сортировки слияния по убыванию массива пар <элемент, индекс в изначальном массиве> (индекс нужен для восстановления ответа).

Модификация известная и состоит в следующем: когда мы сравниваем текущие элементы левого и правого массивов left[i] и right[j], то при left[i] > right[j] все дальнейшие элементы правого массива также меньше (мы сортируем по убыванию), поэтому мы прибавляем к ответу для left[i] число (right.length — j + 1).

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

Если за O(n logn) устроит, то так:

std::vector<size_t> GetAns(const std::vector<int>& a)
{
    const size_t n = a.size();
    std::vector<size_t> b(n);
    std::multiset<int> r;
    for (size_t i = n; i > 0; i--)
    {
        b[i - 1] = std::distance(r.begin(), r.lower_bound(a[i - 1]));
        r.insert(a[i - 1]);
    }
    return b;
}

UPD: это неправильно, ошибся с std::distance.

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

    У multiset не random-access итераторы — distance будет за линию работать в худшем.