제출 #1307577

#제출 시각아이디문제언어결과실행 시간메모리
1307577bbeksneckkArranging Tickets (JOI17_arranging_tickets)Pypy 3
0 / 100
139 ms48596 KiB
import sys

# Увеличиваем лимит рекурсии на всякий случай, хотя используем итеративный подход
sys.setrecursionlimit(200000)

def solve():
    # Быстрый ввод
    input = sys.stdin.read
    data = input().split()
    iterator = iter(data)
    
    try:
        N = int(next(iterator))
        M = int(next(iterator))
    except StopIteration:
        return

    requests = []
    # Считываем запросы
    for _ in range(M):
        u = int(next(iterator))
        v = int(next(iterator))
        c = int(next(iterator))
        
        if u == v:
            continue
            
        # Нормализуем путь как линейный отрезок [start, end)
        # Билет i соединяет станции i и i+1.
        # Станции нумеруются 1..N. Билеты 1..N.
        # Путь от u до v по линейке (без перехода N-1) занимает билеты
        # с индексами от min(u, v) до max(u, v) - 1.
        # Индексы билетов делаем 0-based: 1 -> 0 ... N -> N-1
        
        start = min(u, v)
        end = max(u, v)
        
        # Длина линейного пути
        linear_len = end - start
        # Длина пути через границу (обходного)
        cross_len = N - linear_len
        
        # Мы храним запросы в формате:
        # (Длина обходного пути, левая граница билетов, правая граница билетов, кол-во людей)
        # Левая граница включительно, правая не включительно (Python style range)
        # Билет i (1-based) -> индекс i-1
        requests.append((cross_len, start - 1, end - 1, c))

    # Сортируем запросы: сначала выгоднее перекидывать те, у которых обходной путь короче
    # (они меньше нагружают систему при перевороте)
    requests.sort(key=lambda x: x[0])

    # 1. Строим базовую нагрузку (все идут линейно)
    # Используем разностный массив для быстрого построения
    diff = [0] * (N + 1)
    for _, l, r, c in requests:
        diff[l] += c
        diff[r] -= c
    
    base_load = [0] * N
    curr = 0
    for i in range(N):
        curr += diff[i]
        base_load[i] = curr

    # 2. Дерево отрезков для отслеживания максимума
    # Размер дерева должен быть степенью двойки
    size = 1
    while size < N:
        size *= 2
    
    tree = [0] * (2 * size)
    lazy = [0] * (2 * size)

    # Построение дерева
    def build():
        for i in range(N):
            tree[size + i] = base_load[i]
        for i in range(size - 1, 0, -1):
            tree[i] = max(tree[2*i], tree[2*i+1])

    build()

    def update(l, r, val):
        # Итеративное обновление на отрезке [l, r)
        l += size
        r += size
        l0, r0 = l, r
        
        while l < r:
            if l & 1:
                apply(l, val)
                l += 1
            if r & 1:
                r -= 1
                apply(r, val)
            l //= 2
            r //= 2
            
        # Обновление пути к корню
        l, r = l0, r0
        while l > 1:
            l //= 2
            r //= 2 # для r не нужно точное соответствие, просто поднимаемся
            # Для корректного обновления родителей нужно пройтись по всем затронутым
            # Но в итеративном варианте с lazy проще сделать pull после всего
            pass
        
        # Полный пересчет затронутых веток (медленнее, но надежнее для max)
        # Оптимизированный вариант:
        l = l0
        r = r0 - 1
        while l > 1:
            l //= 2
            push_up(l)
        while r > 1:
            r //= 2
            push_up(r)

    def apply(idx, val):
        tree[idx] += val
        lazy[idx] += val

    def push_up(idx):
        # Значение узла = max(детей) + собственное lazy
        # Важно: lazy не спускаем вниз в этой реализации, а учитываем при чтении
        # Но для max операции lazy нужно прибавлять к результату детей
        val_left = tree[2*idx]
        val_right = tree[2*idx+1]
        tree[idx] = max(val_left, val_right) + lazy[idx]

    # Начальный ответ (без переворотов)
    min_max_load = tree[1]
    
    current_global_offset = 0
    
    # 3. Жадный перебор
    for _, l, r, c in requests:
        # Переворачиваем запрос:
        # Вместо пути [l, r) (линейного) используем дополнение.
        # Математически: Load_new = Load_old + C (везде) - 2C (на отрезке [l, r))
        
        # Добавляем C глобально (просто в переменную)
        current_global_offset += c
        
        # Вычитаем 2C на отрезке [l, r) в дереве
        update(l, r, -2 * c)
        
        # Текущий максимум = Максимум в дереве + глобальное смещение
        current_max = tree[1] + current_global_offset
        if current_max < min_max_load:
            min_max_load = current_max

    print(min_max_load)

if __name__ == '__main__':
    solve()

컴파일 시 표준 출력 (stdout) 메시지

Compiling 'arranging_tickets.py'...

=======
  adding: __main__.pyc (deflated 45%)

=======
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...