Problem:


Score : 600 points

Problem Statement

We have N points numbered 1 to N arranged in a line in this order.

Takahashi decides to make an undirected graph, using these points as the vertices.
In the beginning, the graph has no edge. Takahashi will do M operations to add edges in this graph.
The i-th operation is as follows:

The operation uses integers L_i and R_i between 1 and N (inclusive), and a positive integer C_i. For every pair of integers (s, t) such that L_i \leq s < t \leq R_i, add an edge of length C_i between Vertex s and Vertex t.

The integers L_1, ..., L_M, R_1, ..., R_M, C_1, ..., C_M are all given as input.

Takahashi wants to solve the shortest path problem in the final graph obtained. Find the length of the shortest path from Vertex 1 to Vertex N in the final graph.

Constraints

2 \leq N \leq 10^5

1 \leq M \leq 10^5

1 \leq L_i < R_i \leq N

1 \leq C_i \leq 10^9

Input

Input is given from Standard Input in the following format:

N M
L_1 R_1 C_1
:
L_M R_M C_M

Output

Print the length of the shortest path from Vertex 1 to Vertex N in the final graph.
If there is no shortest path, print -1 instead.

Sample Input 1

4 3
1 3 2
2 4 3
1 4 6

Sample Output 1

5

We have an edge of length 2 between Vertex 1 and Vertex 2, and an edge of length 3 between Vertex 2 and Vertex 4, so there is a path of length 5 between Vertex 1 and Vertex 4.

Sample Input 2

4 2
1 2 1
3 4 2

Sample Output 2

-1

Sample Input 3

10 7
1 5 18
3 4 8
1 3 5
4 7 10
5 9 8
6 10 5
8 10 3

Sample Output 3

28



Sample input:
4 3
1 3 2
2 4 3
1 4 6


Sample output:
5

Submission status: Accepted

Solution code:
# -*- coding: utf-8 -*-

#############
# Libraries #
#############

import sys
input = sys.stdin.readline
sys.setrecursionlimit(1000000)

import math
#from math import gcd
import bisect
import heapq
from collections import defaultdict
from collections import deque
from collections import Counter
from functools import lru_cache

#############
# Constants #
#############

MOD = 10**9+7
INF = float('inf')
AZ = "abcdefghijklmnopqrstuvwxyz"

#############
# Functions #
#############

######INPUT######
def I(): return int(input().strip())
def S(): return input().strip()
def IL(): return list(map(int,input().split()))
def SL(): return list(map(str,input().split()))
def ILs(n): return list(int(input()) for _ in range(n))
def SLs(n): return list(input().strip() for _ in range(n))
def ILL(n): return [list(map(int, input().split())) for _ in range(n)]
def SLL(n): return [list(map(str, input().split())) for _ in range(n)]


#####Shorten#####
def DD(arg): return defaultdict(arg)

#####Inverse#####
def inv(n): return pow(n, MOD-2, MOD)

######Combination######
kaijo_memo = []
def kaijo(n):
  if(len(kaijo_memo) > n): return kaijo_memo[n]
  if(len(kaijo_memo) == 0): kaijo_memo.append(1)
  while(len(kaijo_memo) <= n): kaijo_memo.append(kaijo_memo[-1] * len(kaijo_memo) % MOD)
  return kaijo_memo[n]

gyaku_kaijo_memo = []
def gyaku_kaijo(n):
  if(len(gyaku_kaijo_memo) > n): return gyaku_kaijo_memo[n]
  if(len(gyaku_kaijo_memo) == 0): gyaku_kaijo_memo.append(1)
  while(len(gyaku_kaijo_memo) <= n): gyaku_kaijo_memo.append(gyaku_kaijo_memo[-1] * pow(len(gyaku_kaijo_memo),MOD-2,MOD) % MOD)
  return gyaku_kaijo_memo[n]

def nCr(n,r):
  if n == r: return 1
  if n < r or r < 0: return 0
  ret = 1
  ret = ret * kaijo(n) % MOD
  ret = ret * gyaku_kaijo(r) % MOD
  ret = ret * gyaku_kaijo(n-r) % MOD
  return ret

######Factorization######
def factorization(n):
  arr = []
  temp = n
  for i in range(2, int(-(-n**0.5//1))+1):
    if temp%i==0:
      cnt=0
      while temp%i==0: 
        cnt+=1 
        temp //= i
      arr.append([i, cnt])
  if temp!=1: arr.append([temp, 1])
  if arr==[]: arr.append([n, 1])
  return arr

#####MakeDivisors######
def make_divisors(n):
  divisors = []
  for i in range(1, int(n**0.5)+1):
    if n % i == 0:
      divisors.append(i)
      if i != n // i: 
        divisors.append(n//i)
  return divisors

#####MakePrimes######
def make_primes(N):
  max = int(math.sqrt(N))
  seachList = [i for i in range(2,N+1)]
  primeNum = []
  while seachList[0] <= max:
    primeNum.append(seachList[0])
    tmp = seachList[0]
    seachList = [i for i in seachList if i % tmp != 0]
  primeNum.extend(seachList)
  return primeNum

#####GCD#####
def gcd(a, b):
    while b: a, b = b, a % b
    return a

#####LCM#####
def lcm(a, b):
    return a * b // gcd (a, b)

#####BitCount#####
def count_bit(n):
  count = 0
  while n:
    n &= n-1
    count += 1
  return count

#####ChangeBase#####
def base_10_to_n(X, n):
  if X//n: return base_10_to_n(X//n, n)+[X%n]
  return [X%n]

def base_n_to_10(X, n):
  return sum(int(str(X)[-i-1])*n**i for i in range(len(str(X))))

def base_10_to_n_without_0(X, n):
  X -= 1
  if X//n: return base_10_to_n_without_0(X//n, n)+[X%n]
  return [X%n]

#####IntLog#####
def int_log(n, a):
  count = 0
  while n>=a:
    n //= a
    count += 1
  return count

#############
# Main Code #
#############

class SegmentTree:
  def __init__(self, n, op, e):
    self.n = n
    self.op = op
    self.e = e
    self.size = 2 ** ((n - 1).bit_length())
    self.node = [self.e] * (2 * self.size)
 
  def build(self, array):
    for i in range(self.n):
      self.node[self.size + i] = array[i]
    for i in range(self.size - 1, 0, -1):
      self.node[i] = self.op(self.node[i << 1], self.node[(i << 1) + 1])
 
  def update(self, i, val):
    i += self.size
    self.node[i] = val
    while i > 1:
      i >>= 1
      self.node[i] = self.op(self.node[i << 1], self.node[(i << 1) + 1])
 
  def get(self, l, r):
    l, r = l + self.size, r + self.size
    res_l, res_r = self.e, self.e
    while l < r:
      if l & 1:
        res_l = self.op(res_l, self.node[l])
        l += 1
      if r & 1:
        r -= 1
        res_r = self.op(self.node[r], res_r) 
      l, r = l >> 1, r >> 1
    return self.op(res_l, res_r)
  
N,M = IL()
data = ILL(M)
data.sort()

ST = SegmentTree(N+100,min,INF)
ST.update(1,0)
for l,r,c in data:
  ST.update(r,min(ST.get(r,r+1),ST.get(l,N+10)+c))
  
ans = ST.get(N,N+1)
if ans==INF:
  print(-1)
else:
  print(ans)

Submission status: Accepted

Solution code:
class SegmentTree:

    def __init__(self, n, op, e):
        """
        :param n: 要素数
        :param op: 二項演算
        :param e: 単位減
        """
        self.n = n
        self.op = op
        self.e = e
        self.size = 1 << (self.n - 1).bit_length()      # st[self.size + i] = array[i]
        self.tree = [self.e] * (self.size << 1)

    def built(self, array):
        """arrayを初期値とするセグメント木を構築"""
        for i in range(self.n):
            self.tree[self.size + i] = array[i]
        for i in range(self.size - 1, 0, -1):
            self.tree[i] = self.op(self.tree[i<<1], self.tree[(i<<1)|1])

    def update(self, i, x):
        """i 番目の要素を x に更新　(0-indexed) """
        i += self.size
        self.tree[i] = x
        while i > 1:
            i >>= 1
            self.tree[i] = self.op(self.tree[i<<1], self.tree[(i<<1)|1])

    def get(self, l, r):
        """ [l, r)の区間取得の結果を返す　(0-indexed) """
        l += self.size
        r += self.size
        res_l = self.e
        res_r = self.e
        while l < r:
            if l & 1:
                res_l = self.op(res_l, self.tree[l])
                l += 1
            if r & 1:
                r -= 1
                res_r = self.op(self.tree[r], res_r)
            l >>= 1
            r >>= 1
        return self.op(res_l, res_r)

    def max_right(self, l, f):
        """
        以下の条件を両方満たす r を(いずれか一つ)返す
            ・r = l or f(op(a[l], a[l + 1], ..., a[r - 1])) = true
            ・r = n or f(op(a[l], a[l + 1], ..., a[r])) = false
        """
        if l == self.n: return self.n
        l += self.size
        sm = self.e
        while True:
            while l % 2 == 0: l >>= 1
            if not f(self.op(sm, self.tree[l])):
                while l < self.size:
                    l = 2 * l
                    if f(self.op(sm, self.tree[l])):
                        sm = self.op(sm, self.tree[l])
                        l += 1
                return l - self.size
            sm = self.op(sm, self.tree[l])
            l += 1
            if (l & -l) == l: break
        return self.n

    def min_left(self, r, f):
        """
        以下の条件を両方満たす l を(いずれか一つ)返す
            ・l = r or f(op(a[l], a[l + 1], ..., a[r - 1])) = true
            ・l = 0 or f(op(a[l - 1], a[l], ..., a[r - 1])) = false
        """
        if r == 0: return 0
        r += self.size
        sm = self.e
        while True:
            r -= 1
            while r > 1 and (r % 2): r >>= 1
            if not f(self.op(self.tree[r], sm)):
                while r < self.size:
                    r = 2 * r + 1
                    if f(self.op(self.tree[r], sm)):
                        sm = self.op(self.tree[r], sm)
                        r -= 1
                return r + 1 - self.size
            sm = self.op(self.tree[r], sm)
            if (r & -r) == r: break
        return 0

    def __getitem__(self, i):
        return self.get(i,i+1)

    def __iter__(self):
        for a in self.tree[self.size:self.size+self.n]:
            yield a

    def __str__(self):
        return str(self.tree[self.size:self.size+self.n])

##################################################################################################################
import sys
input = sys.stdin.readline

N, M = map(int, input().split())

e = 1<<60
op = lambda x, y: x if x<y else y
st = SegmentTree(N, op, e)
query = []
st.update(0,0)
for _ in range(M):
    L, R, C = map(int, input().split())
    query.append((L-1, R-1, C))
query.sort(key=lambda x:x[1])
for L, R, C in query:
    tmp = st.get(L, R) + C
    if st[R] > tmp:
        st.update(R,tmp)
print(st[N-1] if st[N-1]!=e else -1)

Submission status: Accepted

Solution code:
import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()
from heapq import heappop, heappush
def resolve():
    n, m = map(int, input().split())
    N = 1 << (n - 1).bit_length()
    N2, now = N * 2, N * 3
    E = [[] for _ in range(N * 3 + m * 2)]
    ref = lambda v : v if v < 3 * N else v - N2

    # build range-edge graph
    for i in range(N - 1, 0, -1):
        cl, cr = i << 1, i << 1 | 1
        E[i].append((cl, 0))
        E[i].append((cr, 0))
        E[ref(cl + N2)].append((ref(i + N2), 0))
        E[ref(cr + N2)].append((ref(i + N2), 0))

    # add range-edge
    for _ in range(m):
        u, v, w = map(int, input().split())
        u -= 1
        # lower
        l, r = u + N, v + N
        while l < r:
            if l & 1:
                E[ref(l + N2)].append((now, 0))
                l += 1
            if r & 1:
                r -= 1
                E[ref(r + N2)].append((now, 0))
            l >>= 1
            r >>= 1
        # upper
        l, r = u + N, v + N
        while l < r:
            if l & 1:
                E[now + 1].append((l, 0))
                l += 1
            if r & 1:
                r -= 1
                E[now + 1].append((r, 0))
            l >>= 1
            r >>= 1
        # range-edge
        E[now].append((now + 1, w))
        now += 2

    # Dijkstra (source : N, termination : N + n - 1)
    dist = [INF] * now
    dist[N] = 0
    heap = [(0, N)]
    while heap:
        d, v = heappop(heap)
        if dist[v] != d:
            continue
        for nv, w in E[v]:
            if dist[nv] > d + w:
                dist[nv] = d + w
                heappush(heap, (d + w, nv))

    ans = dist[N + n - 1]
    if ans == INF:
        ans = -1
    print(ans)
resolve()

Submission status: Accepted

Solution code:
import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()
from heapq import heappop, heappush
def resolve():
    n, m = map(int, input().split())
    N = 1 << (n - 1).bit_length()
    N2, now = N << 1, N << 2
    E = [[] for _ in range((N << 2) + (m << 1))]

    # build range-edge graph
    for i in range(N, N2):
        E[i].append((i + N2, 0))
    for i in range(N - 1, 0, -1):
        cl, cr = i << 1, i << 1 | 1
        E[i].append((cl, 0))
        E[i].append((cr, 0))
        E[cl + N2].append((i + N2, 0))
        E[cr + N2].append((i + N2, 0))

    # add range-edge
    for _ in range(m):
        u, v, w = map(int, input().split())
        u -= 1
        # lower
        l, r = u + N, v + N
        while l < r:
            if l & 1:
                E[l + N2].append((now, 0))
                l += 1
            if r & 1:
                r -= 1
                E[r + N2].append((now, 0))
            l >>= 1
            r >>= 1
        # upper
        l, r = u + N, v + N
        while l < r:
            if l & 1:
                E[now + 1].append((l, 0))
                l += 1
            if r & 1:
                r -= 1
                E[now + 1].append((r, 0))
            l >>= 1
            r >>= 1
        # range-edge
        E[now].append((now + 1, w))
        now += 2

    # Dijkstra (source : N, termination : N + n - 1)
    dist = [INF] * now
    dist[N] = 0
    heap = [(0, N)]
    while heap:
        d, v = heappop(heap)
        if dist[v] != d:
            continue
        for nv, w in E[v]:
            if dist[nv] > d + w:
                dist[nv] = d + w
                heappush(heap, (d + w, nv))

    ans = dist[N + n - 1]
    if ans == INF:
        ans = -1
    print(ans)
resolve()

Submission status: Accepted

Solution code:
import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()

class SegmentTree(object):
    def __init__(self, A, dot, unit):
        n = 1 << (len(A) - 1).bit_length()
        tree = [unit] * (2 * n)
        for i, v in enumerate(A):
            tree[i + n] = v
        for i in range(n - 1, 0, -1):
            tree[i] = dot(tree[i << 1], tree[i << 1 | 1])
        self._n = n
        self._tree = tree
        self._dot = dot
        self._unit = unit

    def __getitem__(self, i):
        return self._tree[i + self._n]

    def update(self, i, v):
        i += self._n
        self._tree[i] = v
        while i != 1:
            i >>= 1
            self._tree[i] = self._dot(self._tree[i << 1], self._tree[i << 1 | 1])

    def add(self, i, v):
        self.update(i, self[i] + v)

    def sum(self, l, r):
        l += self._n
        r += self._n
        l_val = r_val = self._unit
        while l < r:
            if l & 1:
                l_val = self._dot(l_val, self._tree[l])
                l += 1
            if r & 1:
                r -= 1
                r_val = self._dot(self._tree[r], r_val)
            l >>= 1
            r >>= 1
        return self._dot(l_val, r_val)

def resolve():
    n, m = map(int, input().split())
    E = [[] for _ in range(n)]
    for _ in range(m):
        u, v, w = map(int, input().split())
        u -= 1; v -= 1
        E[u].append((v, w))

    tree = SegmentTree([INF] * n, min, INF)
    tree.update(0, 0)
    for v in range(n):
        for nv, w in E[v]:
            tree.update(nv, min(tree[nv], tree.sum(v, nv) + w))

    ans = tree[n - 1]
    if ans == INF:
        ans = -1
    print(ans)
resolve()

Submission status: Accepted

Solution code:
import sys
INF = 1 << 60
MOD = 10**9 + 7 # 998244353
sys.setrecursionlimit(2147483647)
input = lambda:sys.stdin.readline().rstrip()

class SegmentTree(object):
    def __init__(self, A, dot, unit):
        n = 1 << (len(A) - 1).bit_length()
        tree = [unit] * (2 * n)
        for i, v in enumerate(A):
            tree[i + n] = v
        for i in range(n - 1, 0, -1):
            tree[i] = dot(tree[i << 1], tree[i << 1 | 1])
        self._n = n
        self._tree = tree
        self._dot = dot
        self._unit = unit

    def __getitem__(self, i):
        return self._tree[i + self._n]

    def update(self, i, v):
        i += self._n
        self._tree[i] = v
        while i != 1:
            i >>= 1
            self._tree[i] = self._dot(self._tree[i << 1], self._tree[i << 1 | 1])

    def add(self, i, v):
        self.update(i, self[i] + v)

    def sum(self, l, r):
        l += self._n
        r += self._n
        l_val = r_val = self._unit
        while l < r:
            if l & 1:
                l_val = self._dot(l_val, self._tree[l])
                l += 1
            if r & 1:
                r -= 1
                r_val = self._dot(self._tree[r], r_val)
            l >>= 1
            r >>= 1
        return self._dot(l_val, r_val)

def resolve():
    n, m = map(int, input().split())
    edges = []
    for _ in range(m):
        u, v, w = map(int, input().split())
        u -= 1; v -= 1
        edges.append((u, v, w))
    edges.sort()

    tree = SegmentTree([INF] * n, min, INF)
    tree.update(0, 0)
    for u, v, w in edges:
        tree.update(v, min(tree[v], tree.sum(u, v) + w))

    ans = tree[n - 1]
    if ans == INF:
        ans = -1
    print(ans)
resolve()

Submission status: Accepted

Solution code:
class SegmentTree():
  def __init__(self, n, mapping, id):
    self.n = n
    self.id = id
    self.log = (n - 1).bit_length()
    self.size = 1 << self.log
    self.data = [self.id] * (2 * self.size)
    self.mapping = mapping
  
  def get(self, p):
    #assert 0 <= p < self.n
    res = self.id
    p += self.size
    for _ in range(self.log+1):
      res = self.mapping(res, self.data[p])
      p >>= 1
    return res

  def set(self, p, x):
    #assert 0 <= p < self.n
    p += self.size
    self.data[p] = x

  def range_set(self, l, r, x):
    #assert 0 <= l <= r <= self.n
    l += self.size
    r += self.size
    while l < r:
      if l & 1:
        self.data[l] = self.mapping(self.data[l], x)
        l += 1
      if r & 1:
        r -= 1
        self.data[r] = self.mapping(self.data[r], x)
      l >>= 1
      r >>= 1

import sys
input = sys.stdin.readline

N, M = map(int, input().split())
id = 10**18
lst = SegmentTree(N,min,id)
lst.set(0,0)
A = [list(map(int, input().split())) for _ in range(M)]
A.sort(key=lambda x:(x[0],x[1]))
for l,r,c in A:
  lst.range_set(l-1,r,lst.get(l-1)+c)
ans = lst.get(N-1)
print(ans if ans<id else -1)

Submission status: Accepted

Solution code:
class SegmentTree():
  def __init__(self, n, INF):
    self.n = n
    self.INF = INF
    self.log = (n - 1).bit_length()
    self.size = 1 << self.log
    self.data = [self.INF] * (2 * self.size)
  
  def get(self, p):
    #assert 0 <= p < self.n
    res = self.INF
    p += self.size
    for _ in range(self.log+1):
      res = min(res, self.data[p])
      p >>= 1
    return res

  def set(self, p, x):
    #assert 0 <= p < self.n
    p += self.size
    self.data[p] = x

  def range_set(self, l, r, x):
    #assert 0 <= l <= r <= self.n
    l += self.size
    r += self.size
    while l < r:
      if l & 1:
        self.data[l] = min(self.data[l], x)
        l += 1
      if r & 1:
        r -= 1
        self.data[r] = min(self.data[r], x)
      l >>= 1
      r >>= 1

import sys
input = sys.stdin.readline

N, M = map(int, input().split())
INF = 10**18
lst = SegmentTree(N,INF)
lst.set(0,0)
A = [list(map(int, input().split())) for _ in range(M)]
A.sort(key=lambda x:(x[0],x[1]))
for l,r,c in A:
  lst.range_set(l-1,r,lst.get(l-1)+c)
ans = lst.get(N-1)
print(ans if ans<INF else -1)

Submission status: Accepted

Solution code:
class LazySegmentTree():
  def __init__(self, n, op, e, mapping, composition, id):
    self.n = n
    self.op = op
    self.e = e
    self.mapping = mapping
    self.composition = composition
    self.id = id
    self.log = (n - 1).bit_length()
    self.size = 1 << self.log
    self.data = [e] * (2 * self.size)
    self.lazy = [id] * (self.size)

  def update(self, k):
    self.data[k] = self.op(self.data[2 * k], self.data[2 * k + 1])

  def all_apply(self, k, f):
    self.data[k] = self.mapping(f, self.data[k])
    if k < self.size:
      self.lazy[k] = self.composition(f, self.lazy[k])

  def push(self, k): # 親の遅延配列の値を子に反映させる
    self.all_apply(2 * k, self.lazy[k])
    self.all_apply(2 * k + 1, self.lazy[k])
    self.lazy[k] = self.id

  def build(self, arr):
    #assert len(arr) == self.n
    for i, a in enumerate(arr):
      self.data[self.size + i] = a
    for i in range(self.size-1,0,-1):
      self.update(i)

  def set(self, p, x):
    #assert 0 <= p < self.n
    p += self.size
    #事前に関係のある遅延配列を全て反映させてしまう
    for i in range(self.log, 0, -1):
      self.push(p >> i)
    self.data[p] = x #値を更新する
    #関係のある区間の値も更新する
    for i in range(1, self.log + 1):
      self.update(p >> i)

  def get(self, p):
    #assert 0 <= p < self.n
    p += self.size
    #関係のある遅延配列を全て反映させる
    for i in range(self.log, 0, -1):
      self.push(p >> i)
    return self.data[p]

  def prod(self, l, r):
    #assert 0 <= l <= r <= self.n
    if l == r: return self.e
    l += self.size
    r += self.size
    for i in range(self.log, 0, -1):
      if ((l >> i) << i) != l: self.push(l >> i)
      if ((r >> i) << i) != r: self.push(r >> i)
    sml = smr = self.e
    while l < r:
      if l & 1:
        sml = self.op(sml, self.data[l])
        l += 1
      if r & 1:
        r -= 1
        smr = self.op(self.data[r], smr)
      l >>= 1
      r >>= 1
    return self.op(sml, smr)

  def all_prod(self):
    return self.data[1]

  def apply(self, p, f):
    #assert 0 <= p < self.n
    p += self.size
    for i in range(self.log, 0, -1):
      self.push(p >> i)
    self.data[p] = self.mapping(f, self.data[p])
    for i in range(1, self.log + 1):
      self.update(p >> i)

  def range_apply(self, l, r, f):
    #assert 0 <= l <= r <= self.n
    if l == r: return
    l += self.size
    r += self.size
    for i in range(self.log, 0, -1):
      if ((l >> i) << i) != l: self.push(l >> i)
      if ((r >> i) << i) != r: self.push((r - 1) >> i)
    l2 = l
    r2 = r
    while l < r:
      if l & 1:
        self.all_apply(l, f)
        l += 1
      if r & 1:
        r -= 1
        self.all_apply(r, f)
      l >>= 1
      r >>= 1
    l = l2
    r = r2
    for i in range(1, self.log + 1):
      if ((l >> i) << i) != l: self.update(l >> i)
      if ((r >> i) << i) != r: self.update((r - 1) >> i)

  def max_right(self, l, g):
    #assert 0 <= l <= self.n
    #assert g(self.e)
    if l == self.n: return self.n
    l += self.size
    for i in range(self.log, 0, -1):
      self.push(l >> i)
    sm = self.e
    while True:
      while l % 2 == 0: l >>= 1
      if not g(self.op(sm, self.data[l])):
        while l < self.size:
          self.push(l)
          l = 2 * l
          if g(self.op(sm, self.data[l])):
            sm = self.op(sm, self.data[l])
            l += 1
        return l - self.size
      sm = self.op(sm, self.data[l])
      l += 1
      if (l & -l) == l: return self.n

  def min_left(self, r, g):
    #assert 0 <= r <= self.n
    #assert g(self.e)
    if r == 0: return 0
    r += self.size
    for i in range(self.log, 0, -1):
      self.push((r - 1) >> i)
    sm = self.e
    while True:
      r -= 1
      while r > 1 and r % 2: r >>= 1
      if not g(self.op(self.data[r], sm)):
        while r < self.size:
          self.push(r)
          r = 2 * r + 1
          if g(self.op(self.data[r], sm)):
            sm = self.op(self.data[r], sm)
            r -= 1
        return r + 1 - self.size
      sm = self.op(self.data[r], sm)
      if (r & -r) == r: return 0

import sys
input = sys.stdin.readline

INF = 10**18

e = INF
id = INF
N, M = map(int, input().split())

lst = LazySegmentTree(N, min, e, min, min, id)
lst.set(0,0)
A = [list(map(int, input().split())) for _ in range(M)]
A.sort(key=lambda x:(x[0],x[1]))
for l,r,c in A:
  lst.range_apply(l-1,r,lst.get(l-1)+c)
ans = lst.get(N-1)
print(ans if ans<INF else -1)

Submission status: Accepted

Solution code:
import sys
from heapq import heappush,heappop,heapify
read=sys.stdin.readline
INF=10**30

def dijkstra(G,s,n):
    que=[(0,s)]
    dist=[INF]*n
    dist[s]=0
    while que:
        mincost,u=heappop(que)
        if(mincost>dist[u]):
            continue
        for c,v in G[u]:
            if(dist[u]+c<dist[v]):
                dist[v]=dist[u]+c
                heappush(que,(dist[v],v))
    return dist

N,M=map(int,read().split())

G=[[] for _ in range(N)]
for i in range(N-1):
    G[i+1].append((0,i))
    
for i in range(M):
    L,R,C=map(int,read().split())
    L-=1;R-=1
    G[L].append((C,R))
    
dist=dijkstra(G,0,N)
ans=dist[N-1]
print(ans if ans!=INF else -1)

Submission status: Accepted

Solution code:
import sys
read=sys.stdin.readline

class segtree:
    def __init__(self,n,op,e):
        self.e=e
        self.op=op
        self.size=1<<(n-1).bit_length()
        self.SEG=[self.e]*(self.size*2)
    
    def update(self,i,x):
        i+=self.size
        self.SEG[i]=x
        
        while i>0:
            i>>=1
            self.SEG[i]=self.op(self.SEG[i*2],self.SEG[i*2+1])
    
    def get(self,i):
        return self.SEG[i+self.size]
    
    def query(self,l,r):
        l+=self.size
        r+=self.size
        
        lres,rres=self.e,self.e
        
        while l<r:
            if l&1:
                lres=self.op(lres,self.SEG[l])
                l+=1
            
            if r&1:
                r-=1
                rres=self.op(rres,self.SEG[r])
            
            l>>=1
            r>>=1
            
        res=self.op(lres,rres)
        return res

INF=float('inf')
N,M=map(int,read().split())

Q=[]
for i in range(M):
    l,r,c=map(int,read().split())
    Q.append((l-1,r-1,c))
Q.sort(key=lambda x:x[0])

seg=segtree(N,min,INF)
seg.update(0,0)
for L,R,C in Q:
    res=seg.query(L,R)+C
    if seg.get(R)>res:
        seg.update(R,res)
ans=seg.get(N-1)
print(ans if ans!=INF else -1)

Submission status: Accepted

Solution code:
import sys
from collections import defaultdict
import networkx as nx

input = sys.stdin.buffer.readline

N, M = map(int, input().split())
LR_dict = defaultdict(lambda: 10 ** 9)
for _ in range(M):
    l, r, c = map(int, input().split())
    LR_dict[(l, r)] = min(LR_dict[(l, r)], c)

G = nx.DiGraph()
G.add_nodes_from(range(1, N + 1))
G.add_weighted_edges_from([(x + 1, x, 0) for x in range(1, N)])
G.add_weighted_edges_from((l, r, c) for (l, r), c in LR_dict.items())

try:
    print(nx.dijkstra_path_length(G, 1, N))
except nx.NetworkXNoPath:
    print(-1)

Submission status: Accepted

Solution code:
import sys,queue,math,copy,itertools,bisect,collections,heapq

class Node:
    def __init__(self,x):
        self.data = x
        self.count = 1
        self.left = None
        self.right = None

def insert(node,x):
    if node is None: return Node(x)
    if node.data == x:
        node.count += 1
    elif x < node.data:
        node.left = insert(node.left,x)
    else:
        node.right = insert(node.right,x)
    return node

def search_min(node):
    if node.left is None: return node.data
    return search_min(node.left)

def delete_min(node):
    if node.left is None:
        if node.count > 1:
            node.count -= 1
        else:
            return node.right
    else:
        node.left = delete_min(node.left)
    return node

def delete(node,x):
    if node:
        if x == node.data:
            if node.count > 1:
                node.count -= 1
            elif node.left is None:
                return node.right
            elif node.right is None:
                return node.left
            else:
                node.data = search_min(node.right)
                node.right = delete_min(node.right)
        elif x < node.data:
            node.left = delete(node.left,x)
        else:
            node.right = delete(node.right,x)
    return node


def main():
    sys.setrecursionlimit(10**7)
    LI = lambda : [int(x) for x in sys.stdin.readline().split()]

    N,M = LI()
    p = [LI() for _ in range(M)]

    p.sort()

    r = [[] for _ in range(N+1)]
    d = 0
    j = 0
    root = None
    for i in range(1,N):
        update = False
        while j < M and p[j][0] == i:
            root = insert(root,d + p[j][2])
            update = True
            r[p[j][1]].append(d + p[j][2])
            j += 1
        for z in r[i]:
            root = delete(root,z)
            update = True
        if root == None:
            print(-1)
            return
        if update:
            d = search_min(root)
    print(d)

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
import sys,queue,math,copy,itertools,bisect,collections,heapq

class Node:
    def __init__(self,x):
        self.data = x
        self.left = None
        self.right = None

def insert(node,x):
    if node is None: return Node(x)
    elif x < node.data:
        node.left = insert(node.left,x)
    else:
        node.right = insert(node.right,x)
    return node

def search_min(node):
    if node.left is None: return node.data
    return search_min(node.left)

def delete_min(node):
    if node.left is None: return node.right
    node.left = delete_min(node.left)
    return node

def delete(node,x):
    if node:
        if x == node.data:
            if node.left is None:
                return node.right
            elif node.right is None:
                return node.left
            else:
                node.data = search_min(node.right)
                node.right = delete_min(node.right)
        elif x < node.data:
            node.left = delete(node.left,x)
        else:
            node.right = delete(node.right,x)
    return node


def main():
    sys.setrecursionlimit(10**7)
    LI = lambda : [int(x) for x in sys.stdin.readline().split()]

    N,M = LI()
    p = [LI() for _ in range(M)]

    p.sort()

    r = [[] for _ in range(N+1)]
    d = 0
    j = 0
    root = None
    for i in range(1,N):
        update = False
        while j < M and p[j][0] == i:
            root = insert(root,d + p[j][2])
            update = True
            r[p[j][1]].append(d + p[j][2])
            j += 1
        for z in r[i]:
            root = delete(root,z)
            update = True
        if root == None:
            print(-1)
            return
        if update:
            d = search_min(root)
    print(d)

if __name__ == '__main__':
    main()

Submission status: Accepted

Solution code:
N,M=map(int,input().split())
lrc = [tuple(map(int,input().split())) for _ in range(M)]
lrc = sorted(lrc)
INF=10**20

class SegTree:
    """ segment tree with point modification and range product. """
    # # https://yukicoder.me/submissions/452850
    def __init__(self, N, data_f = min, data_unit=1<<30):
        self.N = N
        self.data_f = data_f
        self.data_unit = data_unit
        self.data = [self.data_unit] * (N + N)

    def build(self, raw_data):
        data = self.data
        f = self.data_f
        N = self.N
        data[N:] = raw_data[:]
        for i in range(N - 1, 0, -1):
            data[i] = f(data[i << 1], data[i << 1 | 1])

    def set_val(self, i, x):
        data = self.data
        f = self.data_f
        i += self.N
        data[i] = x
        while i > 1:
            data[i >> 1] = f(data[i], data[i ^ 1])
            i >>= 1

    def fold(self, L, R):
        """ compute for [L, R) """
        vL = vR = self.data_unit
        data = self.data
        f = self.data_f
        L += self.N
        R += self.N
        while L < R:
            if L & 1:
                vL = f(vL, data[L])
                L += 1
            if R & 1:
                R -= 1
                vR = f(data[R], vR)
            L >>= 1
            R >>= 1
        return f(vL, vR)

seg = SegTree(N,min,INF)
seg.set_val(0,0)

for i in range(1,M+1):
  l,r,c = lrc[i-1]
  tmp = seg.fold(l-1,r-1)
  seg.set_val(r-1,min(tmp+c, seg.fold(r-1,r)))

ans = seg.fold(N-1,N)
if ans == INF:
  print(-1)
else:
  print(ans)