Vserosbuybuy

Algo guide

Jul 25th, 2020 (edited)
223
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 30.26 KB | None | 0 0
  1. #include <iostream>
  2. #include <vector>
  3. #include <set>
  4. #include <algorithm>
  5.  
  6. using namespace std;
  7.  
  8. // Решето Эратосфена, находит все простые числа до определенного MAX
  9. // Те i, у которых compound[i] == false - простые, их можно, например,
  10. // собрать в вектор простых prime и позже использовать в решении.
  11. // Ссылка на контест по теме: https://informatics.msk.ru/mod/statements/view3.php?id=50999&chapterid=617#1
  12. // Время работы: О(n * log(log(n)))
  13.  
  14. const int MAXN = 1e6;
  15. bool compound[MAXN];
  16.  
  17. void resheto() {
  18.     compound[0] = compound[1] = 1;
  19.     vector<int> prime;
  20.     for (int i = 2; i < MAXN; ++i) {
  21.         if (!compound[i]) {
  22.             for (int j = i * i; j < MAXN; j += i) {
  23.                 compound[j] = 1;
  24.             }
  25.             prime.push_back(i);
  26.         }
  27.     }
  28. }
  29.  
  30. int a[MAXN];
  31.  
  32. // Ссылка на контест по теме: https://informatics.msk.ru/mod/statements/view.php?id=51205
  33. // обычный бинарный поиск, важно, что значения в массиве обязательно должны быть
  34. // отсортированы по неубыванию (или по невозрастанию, но тогда надо сменить знаки)
  35. // Время работы: О(log(n))
  36. void binary_search(int x, int n) {
  37.     int l = -1;
  38.     int r = n;
  39.     int m;
  40.     // левое вхождение, ответ лежит в l (число, меньшее или равное x)
  41.     while (r - l > 1) {
  42.         m = (r + l) / 2;
  43.         if (a[m] > x) {
  44.             r = m;
  45.         }
  46.         else {
  47.             l = m;
  48.         }
  49.     }
  50.     // правое вхождение, ответ лежит в r (число, большее или равное x)
  51.     while (r - l > 1) {
  52.         m = (r + l) / 2;
  53.         if (a[m] < x) {
  54.             l = m;
  55.         }
  56.         else {
  57.             r = m;
  58.         }
  59.     }
  60. }
  61.  
  62. // бинарный поиск по значению на примере поиска квадратного корня из y
  63. // важно, чтобы функция непрерывно неубывала (или невозрастала, тогда надо поменять знаки)
  64. // в даном случае у нас функция f(x) = x * x (мы ищем корень из y путем возведения нашего числа в квадрат),
  65. // она непрерывно возрастает, то есть подходит
  66. void binary_search(double y) {
  67.     double l = -1; // минимальное значение, которое может быть в ответе
  68.     double r = MAXN; // максимальное значение, которое может быть в ответе
  69.     double eps = 0.001; // точность
  70.     double m;
  71.     // левое вхождение, ответ лежит в l (квадратный корень из y)
  72.     while (r - l > eps) {
  73.         m = (r + l) / 2.0;
  74.         if (m * m > y) {
  75.             r = m;
  76.         }
  77.         else {
  78.             l = m;
  79.         }
  80.     }
  81.     // правое вхождение, ответ лежит в r (квадратный корень из y)
  82.     while (r - l > eps) {
  83.         m = (r + l) / 2;
  84.         if (m * m < y) {
  85.             l = m;
  86.         }
  87.         else {
  88.             r = m;
  89.         }
  90.     }
  91.     // в решении такой задачи чаще всего тип вхождения не имеет значения
  92. }
  93.  
  94. vector<int> matr[MAXN];
  95. int matr2[1000][1000];
  96. bool used[MAXN];
  97.  
  98. // Поиск в глубину (DFS)
  99. // Ссылка на контест: https://informatics.msk.ru/mod/statements/view.php?id=52128
  100. // Обходит все вершины графа, достижимые из стартовой (v), идет "в глубину",
  101. // то есть из текущей вершины последовательно запускается из всех ее детей.
  102. // Выходит, что поиск по очереди обойдет все "поддеревья" сыновей
  103. // Время работы: О(n + m)
  104.  
  105. // поиск в глубину на списках смежности
  106. void dfs(int v) {
  107.     used[v] = 1;
  108.     // делаешь что-то в вершине
  109.     for (auto u : matr[v]) {
  110.         // проверяем, что не были в u
  111.         if (!used[u])
  112.             dfs(u);
  113.     }
  114. }
  115.  
  116. // поиск в глубину на матрице смежности (списки смежности всегда лучше)
  117. void dfs(int v, int n) {
  118.     used[v] = 1;
  119.     // делаешь что-то в вершине
  120.     for (int u = 0; u < n; ++u) {
  121.         // проверяем, что ребро из v в u есть и что мы еще не были в u
  122.         if (matr[v][u] && !used[u])
  123.             dfs(u, n);
  124.     }
  125. }
  126.  
  127. // есть ли в графе цикл?
  128. int used[MAXN]; // теперь used содержит int
  129.  
  130. void dfs(int v) {
  131.     used[v] = 1;
  132.     // делаешь что-то в вершине
  133.     for (auto u : matr[v]) {
  134.         // проверяем, что не были в u
  135.         if (!used[u])
  136.             dfs(u);
  137.         else {
  138.             if (used[u] == 1) {
  139.                 // цикл есть
  140.                 exit(0);
  141.             }
  142.         }
  143.     }
  144.     used[v] = 2;
  145. }
  146.  
  147. // топологическая сортировка
  148. // сортирует вершины так, что если ребро ведет из первой во вторую, вторая будет в topsort
  149. // раньше, чем первая (задача про сборку деталей для машины, когда для изготовления детали
  150. // нужны другие детали, поэтому надо найти правильный порядок сборки)
  151. vector<int> topsort;
  152.  
  153. void dfs(int v) {
  154.     used[v] = 1;
  155.     // делаешь что-то в вершине
  156.     for (auto u : matr[v]) {
  157.         // проверяем, что не были в u
  158.         if (!used[u])
  159.             dfs(u);
  160.     }
  161.     topsort.push_back(v);
  162. }
  163.  
  164. // поиск в ширину (BFS) на списках смежности
  165. // Ссылка на контест: https://informatics.msk.ru/mod/statements/view3.php?id=53037&chapterid=1324
  166. // обходит граф, но равномерно расширяется по ребрам от точки запуска
  167. // в отличие от DFS, который идет "в глубину"
  168. // Время работы: О(n + m)
  169.  
  170. #include <queue>
  171.  
  172. // очередь позволяет обходить вершины по слоям
  173. // сначала мы добавим все, достижимые из стартовой (v),
  174. // потом в конец начнут добавляться те, в которые можно попасть уже из них
  175. // но, благодаря очереди, сначала мы всегда обработаем именно первый слой
  176. // и лишь потом перейдем к обработке следующего
  177. void bfs(int v) {
  178.     queue<int> q;
  179.     // добавляем стартовую
  180.     q.push(v);
  181.     used[v] = 1;
  182.     while (q.size()) {
  183.         // достаем вершину, в которой сейчас оказались
  184.         int u = q.front();
  185.         // удаляем ее из очереди
  186.         q.pop();
  187.         // обходим вершины, в которые можно попасть из нее
  188.         for (int i = 0; i < matr[u].size(); ++i) {
  189.             // вершина, в которую идем
  190.             int p = matr[u][i];
  191.             // проверяем, что еще в ней не были
  192.             if (!used[p]) {
  193.                 // если да, то добавляем ее в конец очереди, помечаем,
  194.                 // что она добавлена при помощи used
  195.                 q.push(p);
  196.                 used[p] = 1;
  197.             }
  198.         }
  199.     }
  200. }
  201.  
  202. // BFS, но на матрице смежности (нежелательно)
  203. void bfs(int v, int n) {
  204.     queue<int> q;
  205.     // добавляем стартовую
  206.     q.push(v);
  207.     used[v] = 1;
  208.     while (q.size()) {
  209.         // достаем вершину, в которой сейчас оказались
  210.         int u = q.front();
  211.         // удаляем ее из очереди
  212.         q.pop();
  213.         // обходим все вершины
  214.         for (int p = 0; p < n; ++p) {
  215.             // p - вершина, в которую мы идем.
  216.             // проверяем, что в нее есть ребро из u и что мы еще в ней не были
  217.             if (matr[u][p] && !used[p]) {
  218.                 // если да, то добавляем ее в конец очереди, помечаем,
  219.                 // что она добавлена при помощи used
  220.                 q.push(p);
  221.                 used[p] = 1;
  222.             }
  223.         }
  224.     }
  225. }
  226.  
  227. // Дейкстра, Флойд и Форд-Беллман
  228. // Ссылка на контест: https://informatics.msk.ru/mod/statements/view.php?id=52706
  229.  
  230. // Алгоритм Флойда
  231. // Ищет кратчайшие попарные расстояния между всеми вершинами графа
  232. // (то есть от любой одной до любой другой)
  233. // Как и любой другой алгоритм поиска кратчайшего пути криво отработает
  234. // с отрицательными циклами, но отлично справляется с отрицательными ребрами
  235. // Время работы: О(n^3)
  236.  
  237. // обычно MAXN, если нужен Флойд, около 100, чтобы куб влез по времени
  238. // в matr[i] теперь хранятся пары интов: первое число - вес ребра,
  239. // второе число - номер вершины, в которую идет это ребро из i
  240. vector<pair<int, int>> matr[MAXN];
  241. int dist[MAXN][MAXN];
  242.  
  243. void floid(int n) {
  244.     for (int i = 0; i < n; ++i) {
  245.         // заполняем все расстояния из i сначала бесконечностями
  246.         fill(dist[i], dist[i] + n, inf);
  247.         // между вершинами, связанными ребром, начальное расстояние - это ребро
  248.         // u.second - куда ведет ребро из i, u.first - вес ребра
  249.         for (auto u : matr[i]) {
  250.             dist[i][u.second] = u.first;
  251.         }
  252.     }
  253.     for (int k = 0; k < n; ++k) {
  254.         for (int i = 0; i < n; ++i) {
  255.             for (int j = 0; j < n; ++j) {
  256.                 dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
  257.             }
  258.         }
  259.     }
  260.     // на выходе имеем:
  261.     // если dist[i][j] == inf, то пути из i в j нет, иначе в dist[i][j] будет длина кратчайшего пути
  262. }
  263.  
  264. // Алгоритм Дейкстры
  265. // Ищет кратчайшие расстояния от стартовой до всех вершин графа
  266. // Ломается при отрицательных циклах и отрицательных ребрах
  267. // Время работы зависит от реализации
  268.  
  269. // matr выглядит так же, как во Флойде
  270. // dist[i] - расстояние от стартовой вершины (v) до i
  271.  
  272. // Время работы этого варианта: O(n^2)
  273. // Используется редко, в ситуации, если вершин не очень много, а ребер большое количество,
  274. // например, когда n = 1000, m близко к 1000000
  275. void dijkstra(int v, int n) {
  276.     fill(dist, dist + n, inf);
  277.     // помечаем, что до стартовой из нее самой расстояние 0, до остальных оно пока что inf
  278.     dist[v] = 0;
  279.     while (true) {
  280.         // пара расстояние, номер вершины
  281.         pair<int, int> u = { inf, -1 };
  282.         // ищем вершину, в которой мы еще не были, с минимальным расстоянием до нее
  283.         for (int i = 0; i < n; ++i) {
  284.             if (!used[i] && dist[i] < u.first) {
  285.                 u = { dist[i], i };
  286.             }
  287.         }
  288.         // Если мы были во всех, то в u останутся стандартные значения
  289.         // Если остались какие-то вершины, но в них из стартовой не дойти,
  290.         // то минимальное dist у таких будет inf
  291.         // В обоих случаях завершаем работу
  292.         if (u.second == -1 || u.first == inf) {
  293.             break;
  294.         }
  295.  
  296.         // раз мы все же смогли достать нужную вершины, то помечаем, что
  297.         // побывали в ней
  298.         used[u.second] = 1;
  299.         // обходим всех тех, с кем она связана
  300.         for (int i = 0; i < matr[u.second].size(); ++i) {
  301.             // пара величина ребра, номер вершины, в которую ведет ребро
  302.             auto p = matr[u.second][i];
  303.             if (!used[p.second]) {
  304.                 // пробуем улучшить расстояние при помощи текущей вершины
  305.                 // сравниваем старое расстояние с расстоянием до u.second + длина ребра
  306.                 dist[p.second] = min(dist[p.second], u.first + p.first);
  307.             }
  308.         }
  309.     }
  310. }
  311.  
  312. // Время работы этого варианта: O(m * log(m))
  313. // Можно несложно оптимизировать до O(m * log(n)), но это увеличит размер кода и не сильно его ускорит
  314. // Используется чаще всего
  315. void dijkstra(int v, int n) {
  316.     fill(dist, dist + n, inf);
  317.     set<pair<int, int>> s;
  318.     // добавляем стартовую вершину, расстояние до нее 0
  319.     s.insert({ 0, v });
  320.     while (s.size()) {
  321.         // пара расстояние, номер вершины
  322.         // ищем вершину, в которой мы не были с минимальным расстоянием от стартовой
  323.         auto u = *s.begin();
  324.         s.erase(s.begin());
  325.         while (used[u.second] && s.size()) {
  326.             u = *s.begin();
  327.             s.erase(s.begin());
  328.         }
  329.         // если не нашли, то завершаем работу
  330.         if (s.empty() && used[u.second]) {
  331.             break;
  332.         }
  333.         // если нужная вершина найдена, помечаем, что побывали в ней
  334.         // и проставляем правильное расстояние до нее
  335.         dist[u.second] = u.first;
  336.         used[u.second] = 1;
  337.         // обходим все соседние
  338.         for (int i = 0; i < matr[u.second].size(); ++i) {
  339.             // пара величина ребра, номер вершины, в которую ведет ребро
  340.             auto p = matr[u.second][i];
  341.             // если еще не посещали эту вершину, добавляем в set пару
  342.             // из нового расстояния до нее и ее номера
  343.             if (!used[p.second]) {
  344.                 s.insert({ u.first + p.first, p.second });
  345.             }
  346.         }
  347.     }
  348. }
  349.  
  350. // Алгоритм Форда-Беллмана
  351. // Так же, как и алгоритм Дейкстры ищет кратчайшее расстояние, от стартовой
  352. // до всех вершин, но умеет работать с отрицательными ребрами
  353. // С его помощью можно искать отрицательные циклы
  354. // Время работы: O(m * n)
  355.  
  356. // Структура для хранения ребер, from - из какой вершины,
  357. // to - в какую, cost - вес ребра
  358. struct Edge {
  359.     int from;
  360.     int to;
  361.     int cost;
  362. };
  363.  
  364. // vector ребер графа (третий способ хранить граф - хранить его ребра)
  365. vector<Edge> edges;
  366.  
  367. void ford_bellman(int st, int n, int m) {
  368.     vector<int> dist(n, inf);
  369.     // опять dist[i] - расстояние от стартовой (st) до i, поэтому
  370.     // dist[st] = 0
  371.     dist[st] = 0;
  372.     for (int i = 0; i < n - 1; ++i) {
  373.         // флаг, чтобы закончить раньше, если ничего не меняется
  374.         // это небольшая оптимизация, которая немного ускоряет программу, но она необязательна
  375.         bool change = false;
  376.         for (int j = 0; j < edges.size(); ++j) {
  377.             // достаем очередное ребро, получаем v - вершину, откуда оно идет, и u - вершину, куда
  378.             int v = edges[j].from;
  379.             int u = edges[j].to;
  380.             // проверяем, что вообще достигли v и посчитали для нее какой-то путь
  381.             if (dist[v] < inf) {
  382.                 // если путь до u через это ребро короче предыдущего, то меняем его на более короткий
  383.                 if (dist[u] > dist[v] + edges[j].cost) {
  384.                     dist[u] = dist[v] + edges[j].cost;
  385.                     change = true;
  386.                 }
  387.             }
  388.         }
  389.         if (!change)  break;
  390.     }
  391. }
  392.  
  393. // С восстановлением пути
  394. // к предыдущему коду добавляется массив предков
  395. // в pr[i] хранится вершина, из которой мы попали в i, когда считали кратчайший путь
  396. int pr[MAXN];
  397. // t - вершина, в которую надо восстановить путь
  398. void ford_bellman_paths(int st, int n, int t) {
  399.     // изначально у всех предки -1
  400.     vector<int> pr(n, -1);
  401.     vector<int> dist(n, inf);
  402.     dist[st] = 0;
  403.     for (int i = 0; i < n - 1; ++i) {
  404.         bool change = false;
  405.         for (int j = 0; j < edges.size(); ++j) {
  406.             int v = edges[j].from;
  407.             int u = edges[j].to;
  408.             if (dist[v] < inf) {
  409.                 if (dist[u] > dist[v] + edges[j].cost) {
  410.                     dist[u] = dist[v] + edges[j].cost;
  411.                     // раз новый кратчайший путь в u проходит через v, то v - предок u
  412.                     pr[u] = v;
  413.                     change = true;
  414.                 }
  415.             }
  416.         }
  417.         if (!change)  break;
  418.     }
  419.  
  420.     // Проверяем, есть ли вообще путь в t
  421.     if (dist[t] == inf) {
  422.         // пути нет
  423.     }
  424.     else {
  425.         vector<int> path;
  426.         for (int cur_v = t; cur_v != -1; cur_v = pr[cur_v]) {
  427.             path.push_back(cur_v);
  428.         }
  429.         reverse(path.begin(), path.end());
  430.         // кратчайший путь от st до t лежит в path
  431.     }
  432. }
  433.  
  434.  
  435. // поиск отрицательного цикла при помощи алгоритма Форда-Беллмана
  436. void ford_bellman_negative_cycles(int st, int n, int m) {
  437.     // эта часть повторяет действия в алгоритме с восстановлением пути
  438.     vector<int> pr(n, -1);
  439.     vector<int> dist(n, inf);
  440.     dist[st] = 0;
  441.     // только добавилась эта переменная для хранения последней вершины, для которой
  442.     // мы обновили путь
  443.     int changed_v = -1;
  444.     // но очень важно, что здесь for идет до n, а не до n - 1
  445.     for (int i = 0; i < n; ++i) {
  446.         // на каждой итерации сбрасываем значение, чтобы потом понять, обновляли
  447.         // ли что-то вообще на последней итерации
  448.         changed_v = -1;
  449.         for (int j = 0; j < edges.size(); ++j) {
  450.             int v = edges[j].from;
  451.             int u = edges[j].to;
  452.             if (dist[v] < inf) {
  453.                 if (dist[u] > dist[v] + edges[j].cost) {
  454.                     dist[u] = dist[v] + edges[j].cost;
  455.                     pr[u] = v;
  456.                     // обновили путь до u, поэтому запоминаем это
  457.                     changed_v = u;
  458.                 }
  459.             }
  460.         }
  461.     }
  462.  
  463.     if (changed_v == -1) {
  464.         // отрицательных циклов нет
  465.     }
  466.     else {
  467.         for (int i = 0; i < n - 1; ++i) {
  468.             changed_v = pr[changed_v];
  469.         }
  470.         // теперь changed_v точно лежит на отрицательном цикле
  471.         vector<int> path;
  472.         for (int cur_v = changed_v;; cur_v = pr[cur_v]) {
  473.             if (cur_v == changed_v && path.size() > 0) {
  474.                 break;
  475.             }
  476.             path.push_back(cur_v);
  477.         }
  478.         reverse(path.begin(), path.end());
  479.         // вершины отрицательного цикла теперь лежат в path, в порядке обхода
  480.     }
  481. }
  482.  
  483. // Z-функция и префикс-функция
  484. // Ссылка на контест: https://informatics.msk.ru/mod/statements/view.php?id=53037
  485. // Время работы обоих алгоритмов: O(n), где n - длина строки
  486.  
  487. // Z-функция
  488. // Ссылка на определение и пример: https://neerc.ifmo.ru/wiki/index.php?title=Z-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F#:~:text=Z%2D%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F%20(%D0%B0%D0%BD%D0%B3%D0%BB.,%D1%8F%D0%B2%D0%BB%D1%8F%D0%B5%D1%82%D1%81%D1%8F%20%D0%B8%20%D0%BF%D1%80%D0%B5%D1%84%D0%B8%D0%BA%D1%81%D0%BE%D0%BC%20%D0%B2%D1%81%D0%B5%D0%B9%20%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8%20.&text=%D0%9F%D1%80%D0%B8%D0%BC%D0%B5%D1%87%D0%B0%D0%BD%D0%B8%D0%B5%3A%20%D0%B4%D0%B0%D0%BB%D0%B5%D0%B5%20%D0%B2%20%D0%BA%D0%BE%D0%BD%D1%81%D0%BF%D0%B5%D0%BA%D1%82%D0%B5%20%D1%81%D0%B8%D0%BC%D0%B2%D0%BE%D0%BB%D1%8B%20%D1%81%D1%82%D1%80%D0%BE%D0%BA%D0%B8%20%D0%BD%D1%83%D0%BC%D0%B5%D1%80%D1%83%D1%8E%D1%82%D1%81%D1%8F%20%D1%81%20%D0%BD%D1%83%D0%BB%D1%8F.
  489. vector<int> z_function(string s) {
  490.     int n = (int)s.length();
  491.     vector<int> z(n, 0);
  492.     for (int i = 1, l = 0, r = 0; i < n; ++i) {
  493.         if (i <= r) {
  494.             z[i] = min(r - i + 1, z[i - l]);
  495.         }
  496.         while (i + z[i] < n && s[z[i]] == s[i + z[i]]) {
  497.             ++z[i];
  498.         }
  499.         if (i + z[i] - 1 > r) {
  500.             l = i, r = i + z[i] - 1;
  501.         }
  502.     }
  503.     // z-функция строки лежит в векторе z
  504.     return z;
  505. }
  506.  
  507.  
  508. // Префикс-функция
  509. // Ссылка на определение и пример: https://neerc.ifmo.ru/wiki/index.php?title=%D0%9F%D1%80%D0%B5%D1%84%D0%B8%D0%BA%D1%81-%D1%84%D1%83%D0%BD%D0%BA%D1%86%D0%B8%D1%8F
  510. vector<int> prefix_function(string s) {
  511.     int n = (int)s.length();
  512.     vector<int> pi(n, 0);
  513.     for (int i = 1; i < n; ++i) {
  514.         int j = pi[i - 1];
  515.         while (j > 0 && s[i] != s[j]) {
  516.             j = pi[j - 1];
  517.         }
  518.         if (s[i] == s[j])  ++j;
  519.         pi[i] = j;
  520.     }
  521.     // префикс-функция строки лежит в векторе pi
  522.     return pi;
  523. }
  524.  
  525. // Хеши
  526. // Обычно используются чтобы быстро (за O(1)) понимать, равны ли две строки или подстроки,
  527. // не сравнивая каждый символ
  528. // Время подсчета хешей префиксов строки: O(n)
  529.  
  530. // теперь можно писать в коде слово ll вместо long long, очень удобно
  531. typedef long long ll;
  532.  
  533. // md - модуль хеша, очень большое простое число
  534. const ll md = 1e9 + 7;
  535. // x - множитель
  536. const ll x = 141;
  537.  
  538. // массив степеней множителя
  539. ll degrees[MAXN];
  540. // хеш префиксов строки
  541. ll h[MAXN];
  542.  
  543. // дает нам хеш подстроки исходной строки с символа i по j включительно
  544. ll get_h(int i, int j) {
  545.     return (h[j + 1] + md - h[i] * degrees[j - i + 1] % md) % md;
  546. }
  547.  
  548. // обычно этот код делают в main
  549. void solve() {
  550.     // считаем массив степеней (обязательно берем по модулю, чтобы избежать переполнения)
  551.     degrees[0] = 1;
  552.     for (int i = 1; i < MAXN; ++i) {
  553.         degrees[i] = degrees[i - 1] * x % md;
  554.     }
  555.  
  556.     string s;
  557.     cin >> s;
  558.     h[0] = 0;
  559.     // считаем полиномиальный хеш префиксов строки простенькой динамикой
  560.     for (int i = 0; i < s.length(); ++i) {
  561.         h[i + 1] = h[i] * x + s[i];
  562.         h[i + 1] %= md;
  563.     }
  564.     // Все, теперь можно использовать хеши, чтобы сравнивать строки и подстроки
  565. }
  566.  
  567. // Дерево отрезков
  568.  
  569. #include <iostream>
  570.  
  571. using namespace std;
  572. const int MAX_N = 300000;
  573.  
  574. pair<int, int> tree[2 * MAX_N];
  575. int a[MAX_N];
  576.  
  577. void build(int v, int l, int r) {
  578.     // v - номер вершины в дереве
  579.     // l, r - границы полуинтервала [l, r) массива, за который отвечает вершина
  580.    
  581.     // Мы попали в лист, отвечающий за один элемент массива
  582.     if (r - l == 1) {
  583.         tree[v] = { a[l], l };
  584.         return;
  585.     }
  586.     // Иначе заполняем сыновей
  587.     int m = (r + l) / 2;
  588.     build(v * 2, l, m);
  589.     build(v * 2 + 1, m,  r);
  590.     // Создаем свое значение на основе значений сыновей
  591.     tree[v] = max(tree[v * 2], tree[v * 2 + 1]);
  592. }
  593.  
  594. // Функция для изменения элемента массива (запрос изменения)
  595. void set(int v, int l, int r, int k, int x) {
  596.     // v - номер вершины в дереве
  597.     // l, r - границы полуинтервала [l, r) массива, за который отвечает вершина
  598.     // k - индекс элемента, который надо изменить
  599.     // x - новое значение элемента
  600.  
  601.     // Если попали в лист, то это точно тот элемент, который мы ищем, из-за алгоритма
  602.     if (r - l == 1) {
  603.         tree[v].first = x;
  604.         return;
  605.     }
  606.     int m = (r + l) / 2;
  607.     // Спускаемся в того сына, в котором находится элемент, который надо поменять
  608.     if (k < m) {
  609.         set(v * 2, l, m, k, x);
  610.     } else {
  611.         set(v * 2 + 1, m, r, k, x);
  612.     }
  613.     // Обновляем вершину на основе сыновей, так как один из них мог поменяться
  614.     tree[v] = max(tree[v * 2], tree[v * 2 + 1]);
  615. }
  616.  
  617. // Функция для поиска максимума на отрезке [l, r) (запрос максимума)
  618. pair<int,int> maximum(int v, int tl, int tr, int l, int r) {
  619.     // v - номер вершины в дереве
  620.     // tl, tr - границы полуинтервала [tl, tr) массива, за который отвечает вершина
  621.     // l, r - границы полуинтервала [l, r) массива, на котором мы ищем максимум
  622.    
  623.     // Если отрезкок вершины полностью попадает в искомый отрезок
  624.     if (l <= tl && tr <= r) {
  625.         return tree[v];
  626.     }
  627.     // Если отрезок вершины не пересекается с искомым (мы попали в нее случайно)
  628.     if (l >= tr || r <= tl) {
  629.         // возвращаем нейтральный элемент
  630.         return {-1e9,-1};
  631.     }
  632.     int m = (tr + tl) / 2;
  633.     // Создаем ответ на основе ответов сыновей
  634.     return  max(maximum(v * 2, tl, m, l, r), maximum(v * 2 + 1, m, tr, l, r));
  635. }
  636.  
  637. int main() {
  638.     int n;
  639.     cin >> n;
  640.     for (int i = 0; i < n; ++i) {
  641.         cin >> a[i];
  642.     }
  643.     build(1, 0, n);
  644.     int q,l,r ;
  645.     cin >> q;
  646.     for (int i = 0; i < q; ++i) {
  647.         char x;
  648.         cin>>x;
  649.         if(x=='s'){
  650.             cin>>l>>r;
  651.             cout << maximum(1, 0, n, l-1, r).second + 1 << " ";
  652.         }
  653.         else if(x=='u'){
  654.             cin>>l>>r;
  655.             set(1,0,n,l-1,r);
  656.         }
  657.     }
  658. }
  659.  
  660. #include <iostream>
  661.  
  662. using namespace std;
  663. const int MAX_N = 100000;
  664.  
  665. int tree[2 * MAX_N];
  666. int a[MAX_N];
  667.  
  668. void build(int v, int l, int r) {
  669.     if (r - l == 1) {
  670.         tree[v] = a[l];
  671.         return;
  672.     }
  673.     int m = (r + l) / 2;
  674.     build(v * 2, l, m);
  675.     build(v * 2 + 1, m,  r);
  676.     tree[v] = tree[v * 2] + tree[v * 2 + 1];
  677. }
  678.  
  679. void set(int v, int l, int r, int k, int x) {
  680.     if (r - l == 1) {
  681.         tree[v] = x;
  682.         return;
  683.     }
  684.     int m = (r + l) / 2;
  685.     if (k < m) {
  686.         set(v * 2, l, m, k, x);
  687.     } else {
  688.         set(v * 2 + 1, m, r, k, x);
  689.     }
  690.     tree[v] = tree[v * 2] + tree[v * 2 + 1];
  691. }
  692.  
  693. int sum(int v, int tl, int tr, int l, int r) {
  694.     if (l <= tl && tr <= r) {
  695.         return tree[v];
  696.     }
  697.     if (l >= tr || r <= tl) {
  698.         return 0;
  699.     }
  700.     int m = (tr + tl) / 2;
  701.     return sum(v * 2, tl, m, l, r) + sum(v * 2 + 1, m, tr, l, r);
  702. }
  703. int main() {
  704.     int n;
  705.     cin >> n;
  706.     for (int i = 0; i < n; ++i) {
  707.         cin >> a[i];
  708.     }
  709.     build(1, 0, n);
  710.     for (int i = 0; i < n * 3; ++i) {
  711.         cout << tree[i] << " ";
  712.     }
  713.     int q, l, r;
  714.     cin >> q;
  715.     for (int i = 0; i < q; ++i) {
  716.         cin >> l >> r;
  717.         cout << sum(1, 0, n, l - 1, r) << "\n";
  718.     }
  719. }
  720.  
Add Comment
Please, Sign In to add comment