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:

from collections import defaultdict
from heapq import heappop, heappush


class Graph():

    def __init__(self):
        self.graph = defaultdict(list)

    def __len__(self):
        return len(self.graph)

    def add_edge(self, src, dst, weight=1):
        self.graph[src].append((dst, weight))

    def get_nodes(self):
        return self.graph.keys()


class Dijkstra():

    def __init__(self, graph, start):
        self.g = graph.graph

        self.dist = defaultdict(lambda: float("inf"))
        self.dist[start] = 0

        self.prev = defaultdict(lambda: None)

        self.Q = []
        heappush(self.Q, (self.dist[start], start))

        while self.Q:
            dist_u, u = heappop(self.Q)

            if self.dist[u] < dist_u:
                continue

            for v, weight in self.g[u]:
                alt = dist_u + weight
                if self.dist[v] > alt:
                    self.dist[v] = alt
                    self.prev[v] = u
                    heappush(self.Q, (alt, v))

    def shortest_distance(self, goal):

        return self.dist[goal]

    def shortest_path(self, goal):
        path = []
        node = goal

        while node is not None:
            path.append(node)
            node = self.prev[node]

        return path[::-1]


import sys
input=sys.stdin.readline
n,m=map(int,input().split())
g=Graph()

for _ in range(m):
    l,r,c=map(int,input().split())
    g.add_edge(l,r,c)
for i in range(2,n+1):
    g.add_edge(i,i-1,0)


d = Dijkstra(g,1)
ans=d.shortest_distance(n)
print(ans if ans!=float("inf") else -1)

Submission status: Accepted

Solution code:
"""
#editorialより
頂点1から頂点iへの最短路の長さをdiとするとd1≦d2≦....≦dN
各iに対して頂点i+ 1から頂点iに長さ0の辺を追加
このときi回目に追加される辺について考えると、
頂点Liから頂点Riへの長さCiの辺を追加すれば十分
"""
import sys,heapq
input = sys.stdin.readline

n,m = map(int,input().split( ))
Ad = [[] for _ in range(n)]
for i in range(m):
    li,ri,ci = map(int, input().split( ))
    Ad[li-1].append((ri-1,ci))
for i in range(1,n):
    Ad[i].append((i-1,0))

inf = 10**20###これ不十分だった
D = [inf for _ in range(n)]
#Prev = [-1 for _ in range(n)]
D[0] = 0
Q = []
heapq.heappush(Q, (0,0))

while Q:
    d,q = heapq.heappop(Q) #qは[距離、頂点番号]：キューの優先度の都合で番号が後
    #print(q)
    for v,c in Ad[q]:
        if D[v]>d+c:
            D[v] = d+c
            #Prev[n[0]] = q[1]
            heapq.heappush(Q, (d+c,v))

if D[n-1]<inf:
    print(D[n-1])
else:
    print(-1)

Submission status: Accepted

Solution code:
import sys
import heapq
n, m = map(int, input().split())

nextL = [[] for _ in range(n+1)]
for i in range(2, n+1):
    nextL[i].append([i-1, 0])

INF = 10**18

costs = [INF] * (n+1)
costs[1] = 0

for i in range(m):
    l, r, c = map(int, sys.stdin.readline().split())
    nextL[l].append([r, c])

pc = []
heapq.heappush(pc, (0, 1))

unreach = set(range(1, n+1))

while len(pc) > 0 :
    cost, target = heapq.heappop(pc)
    if cost > costs[target]:
        continue
    for i in nextL[target]:
        nex = i[0]
        cos = i[1]
        if nex in unreach and cost + cos < costs[nex]:
            costs[nex] = cost + cos
            heapq.heappush(pc, (cost+cos, nex))
    unreach.remove(target)

if costs[n] == INF:
    print(-1)
else:
    print(costs[n])

Submission status: Accepted

Solution code:
from sys import stdin
import heapq

N, M = [int(x) for x in stdin.readline().rstrip().split()]
B = [[int(x) for x in stdin.readline().rstrip().split()] for _ in range(M)]

graph = [[] for _ in range(N)]
for i in range(1, N):
    graph[i].append((0, i - 1))
for m in B:
    graph[m[0] - 1].append((m[2], m[1] - 1))

d = [(0, 0)]
distance = [10 ** 15] * N
distance[0] = 0
color = ['white'] * N
heapq.heapify(d)

while len(d) > 0:
    temp, u = heapq.heappop(d)
    color[u] = 'black'
    if distance[u] < temp:
        continue
    for v in graph[u]:
        if color[v[1]] != 'black':
            if distance[u] + v[0] < distance[v[1]]:
                distance[v[1]] = distance[u] + v[0]
                color[v[1]] = 'gray'
                heapq.heappush(d, (distance[v[1]], v[1]))

if distance[N - 1] == 10 ** 15:
    print(-1)
else:
    print(distance[N - 1])

Submission status: Accepted

Solution code:
from bisect import bisect_left

N, M = map(int, input().split())
LRC = []

for _ in range(M) :
    L, R, C = map(int, input().split())
    LRC.append((L-1, R-1, C))
    
LRC.sort()
LRC.sort(key=lambda x: x[1])

cost_r = [0]
cost_v = [0]
for L, R, C in LRC :
    i = bisect_left(cost_r, L)
    if i == len(cost_r) :
        continue
    nc = cost_v[i] + C
    
    while nc < cost_v[-1] :
        cost_r.pop()
        cost_v.pop()
    
    if R > cost_r[-1] :
        cost_r.append(R)
        cost_v.append(nc)
    
if cost_r[-1] == N - 1 :
    print(cost_v[-1])
else :
    print(-1)

Submission status: Accepted

Solution code:
def update(k,x):
  k+=N0-1
  data[k]=x
  while k>=0:
    k=~-k//2
    data[k]=min(data[2*k+1],data[2*k+2])
def query(l,r):
  L,R=l+N0,r+N0
  s=INF
  while L<R:
    if R&1:
      R-=1
      s=min(s,data[R-1])
    if L&1:
      s=min(s,data[L-1])
      L+=1
    L//=2
    R//=2
  return s
n,m,*t=map(int,open(0).read().split())
N0=2**(n).bit_length()
INF=10**18
data=[INF]*2*N0
update(1,0)
for l,r,c in sorted(zip(*[iter(t)]*3)):update(r,min(data[r+N0-1],query(l,r)+c))
print(data[n+N0-1]%INF or-1)

Submission status: Accepted

Solution code:
import numpy as np
import heapq

INF=10**15
N,M=map(int,input().split())
adj=[[] for i in range(N)]
for i in range(M):
    L,R,C=map(int,input().split())
    L-=1
    R-=1
    adj[L].append((R,C))
    adj[R].append((L,C))
for i in range(N-1):
    adj[i+1].append((i,0))
    
s=0
g=N-1
heap=[]
table=np.array([INF for i in range(N)])
table[s]=0
heapq.heappush(heap,(table[s],s))
                
while heap:
    q=heapq.heappop(heap)
    a=q[1]
    if q[0]>table[a]: continue
    for ne in adj[a]:
        p=ne[0]
        co=ne[1]
        if table[p]>table[a]+co:
            table[p]=table[a]+co
            heapq.heappush(heap,(table[p],p))
ans=table[g]
if ans==INF:
    print(-1)
else:
    print(ans)

Submission status: Accepted

Solution code:
import heapq
import sys

class rode():
    def __init__(self,x,y):
        self.x = x
        self.y = y
    def __lt__(self, other):
        return self.y < other.y
    def __gt__(self, other):
        return other > self
    def __le__(self, other):
        return not(other > self)
    def __ge__(self, other):
        return not(self > other)

n,m = map(int,input().split())
da = [[] for i in range(n)]
for i in range(m):
    l,r,c = map(int,input().split())
    da[l-1].append([r-1,c])
for i in range(1,n):
    da[i].append([i-1,0])
pq=[]
ju = [False for i in range(n)]
ju[0] = True
for i in da[0]:
    heapq.heappush(pq, rode(i[0],i[1]))
while(len(pq)):
    now = heapq.heappop(pq)
    if now.x == n-1:
        print(now.y)
        sys.exit()
    if ju[now.x]:
        continue
    ju[now.x] = True
    for i in da[now.x]:
        if ju[i[0]]:
            continue
        heapq.heappush(pq,rode(i[0],now.y+i[1]))
print(-1)

Submission status: Accepted

Solution code:
import heapq
import numpy as np
import sys

n,m = map(int,input().split())
da = [[] for i in range(n)]
for i in range(1,n):
    da[i].append([i-1,0])
for i in range(m):
    l,r,c = map(int,input().split())
    da[l-1].append([r-1,c])
pq=[]
ju = np.zeros(n,dtype=bool)
ju[0] = True
for i in da[0]:
    heapq.heappush(pq, [i[1],i[0]])
while(len(pq)):
    now = heapq.heappop(pq)
    if now[1] == n-1:
        print(now[0])
        sys.exit()
    if ju[now[1]]:
        continue
    ju[now[1]] = True
    for i in da[now[1]]:
        if ju[i[0]]:
            continue
        heapq.heappush(pq,[now[0]+i[1],i[0]])
print(-1)

Submission status: Accepted

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

import sys
def input(): return sys.stdin.readline().strip()
def list2d(a, b, c): return [[c] * b for i in range(a)]
def list3d(a, b, c, d): return [[[d] * c for k in range(b)] for i in range(a)]
def list4d(a, b, c, d, e): return [[[[e] * d for k in range(c)] for k in range(b)] for i in range(a)]
def ceil(x, y=1): return int(-(-x // y))
def INT(): return int(input())
def MAP(): return map(int, input().split())
def LIST(N=None): return list(MAP()) if N is None else [INT() for i in range(N)]
def Yes(): print('Yes')
def No(): print('No')
def YES(): print('YES')
def NO(): print('NO')
sys.setrecursionlimit(10 ** 9)
INF = 10 ** 18
MOD = 998244353

class SegTree:
    """
    セグメント木
    1.update:  i番目の値をxに更新する
    2.query: 区間[l, r)の値を得る
    """

    def __init__(self, n, func, intv, A=[]):
        """
        :param n: 要素数(0-indexed)
        :param func: 値の操作に使う関数(min, max, add, gcdなど)
        :param intv: 要素の初期値(単位元)
        :param A: 初期化に使うリスト(オプション)
        """
        self.n = n
        self.func = func
        self.intv = intv
        # nより大きい2の冪数
        n2 = 1
        while n2 < n:
            n2 <<= 1
        self.n2 = n2
        self.tree = [self.intv] * (n2 << 1)
        # 初期化の値が決まっている場合
        if A:
            # 1段目(最下段)の初期化
            for i in range(n):
                self.tree[n2+i] = A[i]
            # 2段目以降の初期化
            for i in range(n2-1, -1, -1):
                self.tree[i] = self.func(self.tree[i*2], self.tree[i*2+1])

    def update(self, i, x):
        """
        i番目の値をxに更新
        :param i: index(0-indexed)
        :param x: update value
        """
        i += self.n2
        self.tree[i] = x
        while i > 0:
            i >>= 1
            self.tree[i] = self.func(self.tree[i*2], self.tree[i*2+1])

    def query(self, a, b):
        """
        [a, b)の値を得る
        :param a: index(0-indexed)
        :param b: index(0-indexed)
        """
        l = a + self.n2
        r = b + self.n2
        s = self.intv
        while l < r:
            if r & 1:
                r -= 1
                s = self.func(s, self.tree[r])
            if l & 1:
                s = self.func(s, self.tree[l])
                l += 1
            l >>= 1
            r >>= 1
        return s

    def get(self, i):
        """ 一点取得 """
        return self.tree[i+self.n2]

    def all(self):
        """ 全区間[0, n)の取得 """
        return self.tree[1]

N, M = MAP()
LRC = []
for i in range(M):
    l, r, c = MAP()
    l -= 1
    r -= 1
    LRC.append((l, r, c))

LRC.sort()
st = SegTree(N, min, INF)
st.update(0, 0)
for l, r, c in LRC:
    mn = st.query(l, r)
    if mn+c < st.get(r):
        st.update(r, mn+c)

ans = st.get(N-1)
if ans != INF:
    print(st.get(N-1))
else:
    print(-1)

Submission status: Accepted

Solution code:
"""
双対セグ木
アクセスは0-indexed, 内部のツリーは 1-indexed
関数は閉区間
作用素は右から作用とする

引数：
    N: 処理する区間の長さ
    compose: 作用素を合成させる関数 (max, min, __add__,ラムダ式,関数定義など)
    UNIT: 恒等作用素
    funcval(x,f) = f(x)
"""

class segment_tree_dual:
    def __init__(self, N, compose, funcval, UNIT=None):
        self.compose = compose
        self.UNIT = UNIT
        self.funcval = funcval

        self.height = (N-1).bit_length() #木の高さ
        self.N0 = 1<<self.height #木の横幅 >= N
        self.laz = [self.UNIT]*(2*self.N0) #作用素の木
        self.val = None #値の配列

    #初期値の配列を作る
    def build(self,initial):
        self.val = initial[:]

    #laz[k] を子に伝える、
    def propagate(self,k):
        if self.laz[k] == self.UNIT: return;
        if self.N0 <= k:
            self.val[k-self.N0] = self.funcval(self.val[k-self.N0], self.laz[k])
            self.laz[k] = self.UNIT
        else:
            self.laz[(k<<1)  ] = self.compose(self.laz[(k<<1)  ],self.laz[k]);
            self.laz[(k<<1)+1] = self.compose(self.laz[(k<<1)+1],self.laz[k]);
            self.laz[k] = self.UNIT;
    
    # laz[k]およびその上に位置する作用素をすべて伝播
    def thrust(self,k):
        for i in range(self.height,-1,-1): self.propagate(k>>i)
    
    def thrust_for_update(self,k):
        while k&1 == 0: k//=2
        for i in range(self.height-1,-1,-1): self.propagate(k>>i)

    # 区間[L,R]に関数 f を作用
    def update(self, L,R,f):
        """まず伝播させる（オペレータが可換なら必要ない）"""
        L += self.N0; R += self.N0+1
        self.thrust_for_update(L)
        self.thrust_for_update(R-1)
        
        #[L,R)に対応する区間たちに関数 f を合成
        while L < R:
            if R & 1:
                R -= 1
                self.laz[R] = self.compose(self.laz[R],f)
            if L & 1:
                self.laz[L] = self.compose(self.laz[L],f)
                L += 1
            L >>= 1; R >>= 1
    
    # values[k] を取得。
    def point_get(self, k):
        res = self.val[k]
        k += self.N0
        while k:
            res = self.funcval(res, self.laz[k])
            k //= 2
        return res
    
    # values[k] = x 代入する
    def point_set(self, k): 
        self.thrust(k)
        self.val[k] = x



###########################################################################
#日経2020予選D
#https://atcoder.jp/contests/nikkei2019-2-qual/submissions/8384133 (伝播あり)
#https://atcoder.jp/contests/nikkei2019-2-qual/submissions/8384138 (伝播なし)
###########################################################################

# coding: utf-8
# Your code here!
 
import sys
sys.setrecursionlimit(10**6)
readline = sys.stdin.readline 

n,m = [int(i) for i in readline().split()]
lrc = [tuple(int(i) for i in readline().split()) for _ in range(m)]
lrc.sort()

compose = lambda f,g: min(f,g)
funcval = lambda x,f: min(x,f)
UNIT = INF = 10**18

seg = segment_tree_dual(n, compose, funcval, UNIT)
seg.build([0]+[INF]*(n-1))

for l,r,c in lrc:
    l -= 1
    r -= 1
    v = seg.point_get(l)
    seg.update(l+1,r,v+c)

ans = seg.point_get(n-1)

if ans != INF:
    print(ans)
else:
    print(-1)

Submission status: Accepted

Solution code:
"""
双対セグ木
アクセスは0-indexed, 内部のツリーは 1-indexed
関数は閉区間
作用素は右から作用とする

引数：
    N: 処理する区間の長さ
    compose: 作用素を合成させる関数 (max, min, __add__,ラムダ式,関数定義など)
    UNIT: 恒等作用素
    funcval(x,f) = f(x)
"""

class segment_tree_dual:
    def __init__(self, N, compose, funcval, UNIT=None):
        self.compose = compose
        self.UNIT = UNIT
        self.funcval = funcval

        self.height = (N-1).bit_length() #木の高さ
        self.N0 = 1<<self.height #木の横幅 >= N
        self.laz = [self.UNIT]*(2*self.N0) #作用素の木
        self.val = None #値の配列

    #初期値の配列を作る
    def build(self,initial):
        self.val = initial[:]

    #laz[k] を子に伝える、
    def propagate(self,k):
        if self.laz[k] == self.UNIT: return;
        if self.N0 <= k:
            self.val[k-self.N0] = self.funcval(self.val[k-self.N0], self.laz[k])
            self.laz[k] = self.UNIT
        else:
            self.laz[(k<<1)  ] = self.compose(self.laz[(k<<1)  ],self.laz[k]);
            self.laz[(k<<1)+1] = self.compose(self.laz[(k<<1)+1],self.laz[k]);
            self.laz[k] = self.UNIT;
    
    # laz[k]およびその上に位置する作用素をすべて伝播
    def thrust(self,k):
        for i in range(self.height,-1,-1): self.propagate(k>>i)
    
    def thrust_for_update(self,k):
        while k&1 == 0: k//=2
        for i in range(k.bit_length()-1,-1,-1): self.propagate(k>>i)

    # 区間[L,R]に関数 f を作用
    def update(self, L,R,f):
        """まず伝播させる（オペレータが可換なら必要ない）"""
        L += self.N0; R += self.N0+1
        self.thrust_for_update(L)
        self.thrust_for_update(R-1)
        
        #[L,R)に対応する区間たちに関数 f を合成
        while L < R:
            if R & 1:
                R -= 1
                self.laz[R] = self.compose(self.laz[R],f)
            if L & 1:
                self.laz[L] = self.compose(self.laz[L],f)
                L += 1
            L >>= 1; R >>= 1
    
    # values[k] を取得。
    def point_get(self, k):
        res = self.val[k]
        k += self.N0
        while k:
            res = self.funcval(res, self.laz[k])
            k //= 2
        return res
    
    # values[k] = x 代入する
    def point_set(self, k): 
        self.thrust(k)
        self.val[k] = x



###########################################################################
#日経2020予選D
#https://atcoder.jp/contests/nikkei2019-2-qual/submissions/8384133 (伝播あり)
#https://atcoder.jp/contests/nikkei2019-2-qual/submissions/8384138 (伝播なし)
###########################################################################

# coding: utf-8
# Your code here!
 
import sys
sys.setrecursionlimit(10**6)
readline = sys.stdin.readline 

n,m = [int(i) for i in readline().split()]
lrc = [tuple(int(i) for i in readline().split()) for _ in range(m)]
lrc.sort()

compose = lambda f,g: min(f,g)
funcval = lambda x,f: min(x,f)
UNIT = INF = 10**18

seg = segment_tree_dual(n, compose, funcval, UNIT)
seg.build([0]+[INF]*(n-1))

for l,r,c in lrc:
    l -= 1
    r -= 1
    v = seg.point_get(l)
    seg.update(l+1,r,v+c)

ans = seg.point_get(n-1)

if ans != INF:
    print(ans)
else:
    print(-1)

Submission status: Accepted

Solution code:
import heapq
N,M=map(int,input().split())
path=[[] for _ in range(N)]
for _ in range(M):
  l,r,c=map(int,input().split())
  path[l-1].append([r,c])
for i in range(1,N):
  path[i].append([i,0])

dist=[float("inf")]*N
dist[0]=0
q=[[dist[i],i] for i in range(N)]
heapq.heapify(q)

while q:
  d,ind=heapq.heappop(q)
  if d<=dist[ind]:
    for i in range(len(path[ind])):
      r,c=path[ind][i]
      if dist[r-1]>d+c:
        dist[r-1]=d+c
        heapq.heappush(q,[dist[r-1],r-1])

if dist[N-1]==float("inf"):
  print(-1)
else:
  print(dist[N-1])

Submission status: Accepted

Solution code:
from operator import itemgetter
from collections import defaultdict
from heapq import heappop, heappush

class Graph(object):
    """
    隣接リストによる有向グラフ
    """

    def __init__(self):
        self.graph = defaultdict(list)

    def __len__(self):
        return len(self.graph)

    def add_edge(self, src, dst, weight=1):
        self.graph[src].append((dst, weight))

    def get_nodes(self):
        return self.graph.keys()

class Dijkstra(object):
    """
    ダイクストラ法（二分ヒープ）による最短経路探索
    計算量: O((E+V)logV)
    """

    def __init__(self, graph, start):
        self.g = graph.graph

        # startノードからの最短距離
        # startノードは0, それ以外は無限大で初期化
        self.dist = defaultdict(lambda: float('inf'))
        self.dist[start] = 0

        # 最短経路での1つ前のノード
        self.prev = defaultdict(lambda: None)

        # startノードをキューに入れる
        self.Q = []
        heappush(self.Q, (self.dist[start], start))

        while self.Q:
            # 優先度（距離）が最小であるキューを取り出す
            dist_u, u = heappop(self.Q)
            if self.dist[u] < dist_u:
                continue
            for v, weight in self.g[u]:
                alt = dist_u + weight
                if self.dist[v] > alt:
                    self.dist[v] = alt
                    self.prev[v] = u
                    heappush(self.Q, (alt, v))

    def shortest_distance(self, goal):
        """
        startノードからgoalノードまでの最短距離
        """
        return self.dist[goal]

N,M = [int(x) for x in input().split()]
graph = Graph()
for n in range(N):
    graph.add_edge(n+1, n, 0)
for _ in range(M):
    l, r, c = [int(x) for x in input().split()]
    graph.add_edge(l-1, r-1, weight=c)

dijkstra = Dijkstra(graph, 0)
ans = dijkstra.shortest_distance(N-1)
if(ans == float('inf')):
    print(-1)
else:
    print(ans)

Submission status: Accepted

Solution code:
import heapq
import sys

input = sys.stdin.readline

def dijkstra_heap(s,N,edge):
    d = [float('inf')] * N
    used = [True] * N
    d[s] = 0
    used[s] = False
    edgelist = []
    for a, b in edge[s]:
        heapq.heappush(edgelist, a * (10 ** 6) + b)
    while len(edgelist):
        minedge = heapq.heappop(edgelist)
        if not used[minedge%(10**6)]:
            continue
        v = minedge % (10 ** 6)
        d[v] = minedge // (10 ** 6)
        used[v] = False
        for e in edge[v]:
            if used[e[1]]:
                heapq.heappush(edgelist,(e[0]+d[v])*(10**6)+e[1])
    return d


def main():
    N, M = map(int, input().split())
    edge = [[] for i in range(N)]
    for i in range(N-1):
        edge[i+1].append([0,i])
    for i in range(M):
        L, R, C = map(int, input().split())
        L -= 1
        R -= 1
        edge[L].append([C,R])
        edge[R].append([C,L])
    d = dijkstra_heap(0,N,edge)
    if d[N-1] == float('inf'):
        print(-1)
    else:
        print(d[N-1])
    

if __name__ == "__main__":
    main()

Submission status: Accepted

Solution code:
from heapq import heappush, heappop
import sys
input = sys.stdin.readline

INF = float('inf')

# 単一始点最短経路を求める（Dijkstra法）
def Dijkstra(adjList, vSt):
    numV = len(adjList)
    numUsed = 0
    costs = [INF] * numV
    costs[vSt] = 0
    PQ = []
    heappush(PQ, (0, vSt))
    while PQ:
        cNow, vNow = heappop(PQ)
        if cNow > costs[vNow]: continue
        numUsed += 1
        if numUsed == numV: break
        for v2, wt in adjList[vNow]:
            c2 = cNow + wt
            if c2 < costs[v2]:
                costs[v2] = c2
                heappush(PQ, (c2, v2))
    return costs

N, M = map(int, input().split())
adjL = [[] for _ in range(N)]
for _ in range(M):
    L, R, C = map(int, input().split())
    L, R = L-1, R-1
    adjL[L].append((R, C))
    adjL[R].append((L, C))

for i in range(N-1):
    adjL[i+1].append((i, 0))

costs = Dijkstra(adjL, 0)

if costs[-1] == INF:
    print(-1)
else:
    print(costs[-1])

Submission status: Accepted

Solution code:
"""
双対セグ木
アクセスは0-indexed, 内部のツリーは 1-indexed
つまりすべての和は tree[0]
関数は閉区間
作用素は右から作用とする

引数：
    N: 処理する区間の長さ
    compose: 作用素を合成させる関数 (max, min, __add__,ラムダ式,関数定義など)
    UNIT: 恒等作用素
    funcval(x,f) = f(x)
"""

class segment_tree:
    def __init__(self, N, compose, funcval, UNIT=None):
        self.compose = compose
        self.UNIT = UNIT
        self.funcval = funcval

        self.h = (N-1).bit_length() #木の高さ
        self.N0 = 1<<self.h #木の横幅 >= N
        self.laz = [self.UNIT]*(2*self.N0) #作用素の木
        self.val = None #値の配列

    #初期値の配列を作る
    def build(self,initial):
        self.val = initial[:]

    #laz[k] を子に伝える、
    def propagate(self,k):
        if self.laz[k] == self.UNIT: return;
        if self.N0 <= k:
            self.val[k-self.N0] = self.funcval(self.val[k-self.N0], self.laz[k])
            self.laz[k] = self.UNIT
        else:
            self.laz[(k<<1)  ] = self.compose(self.laz[(k<<1)  ],self.laz[k]);
            self.laz[(k<<1)+1] = self.compose(self.laz[(k<<1)+1],self.laz[k]);
            self.laz[k] = self.UNIT;
    
    # laz[k]およびその上に位置する作用素をすべて伝播
    def thrust(self,k):
        for i in range(self.h,-1,-1): self.propagate(k>>i)

    # 区間[l,r]に関数 f を作用
    def update(self, L,R,f):
        L += self.N0; R += self.N0+1
        """まず伝播させる（オペレータが可換なら必要ない）"""
        #self.thrust(L)
        #self.thrust(R-1)
        #登りながら関数 f を合成
        while L < R:
            if R & 1:
                R -= 1
                self.laz[R] = self.compose(self.laz[R],f)
            if L & 1:
                self.laz[L] = self.compose(self.laz[L],f)
                L += 1
            L >>= 1; R >>= 1
    
    # values[k] を取得。
    def point_get(self, k):
        res = self.val[k]
        k += self.N0
        while k:
            res = self.funcval(res, self.laz[k])
            k //= 2
        return res
    
    # values[k] = x 代入する
    def point_set(self, k): 
        self.thrust(k)
        values[k] = x



###########################################################################
#日経2020予選D

###########################################################################

# coding: utf-8
# Your code here!
 
import sys
sys.setrecursionlimit(10**6)
readline = sys.stdin.readline 

n,m = [int(i) for i in readline().split()]
lrc = [tuple(int(i) for i in readline().split()) for _ in range(m)]
lrc.sort()

compose = lambda f,g: min(f,g)
funcval = lambda x,f: min(x,f)
UNIT = INF = 10**18

seg = segment_tree(n, compose, funcval, UNIT)
seg.build([0]+[INF]*(n-1))

for l,r,c in lrc:
    l -= 1
    r -= 1
    v = seg.point_get(l)
    seg.update(l+1,r,v+c)

ans = seg.point_get(n-1)

if ans != INF:
    print(ans)
else:
    print(-1)

Submission status: Accepted

Solution code:
"""
双対セグ木
アクセスは0-indexed, 内部のツリーは 1-indexed
つまりすべての和は tree[0]
関数は閉区間
作用素は右から作用とする

引数：
    N: 処理する区間の長さ
    compose: 作用素を合成させる関数 (max, min, __add__,ラムダ式,関数定義など)
    UNIT: 恒等作用素
    funcval(x,f) = f(x)
"""

class segment_tree:
    def __init__(self, N, compose, funcval, UNIT=None):
        self.compose = compose
        self.UNIT = UNIT
        self.funcval = funcval

        self.h = (N-1).bit_length() #木の高さ
        self.N0 = 1<<self.h #木の横幅 >= N
        self.laz = [self.UNIT]*(2*self.N0) #作用素の木
        self.val = None #値の配列

    #初期値の配列を作る
    def build(self,initial):
        self.val = initial[:]

    #laz[k] を子に伝える、
    def propagate(self,k):
        if self.laz[k] == self.UNIT: return;
        if self.N0 <= k:
            self.val[k-self.N0] = self.funcval(self.val[k-self.N0], self.laz[k])
            self.laz[k] = self.UNIT
        else:
            self.laz[(k<<1)  ] = self.compose(self.laz[(k<<1)  ],self.laz[k]);
            self.laz[(k<<1)+1] = self.compose(self.laz[(k<<1)+1],self.laz[k]);
            self.laz[k] = self.UNIT;
    
    # laz[k]およびその上に位置する作用素をすべて伝播
    def thrust(self,k):
        for i in range(self.h,-1,-1): self.propagate(k>>i)

    # 区間[l,r]に関数 f を作用
    def update(self, L,R,f):
        L += self.N0; R += self.N0+1
        """まず伝播させる（オペレータが可換なら必要ない）"""
        self.thrust(L)
        self.thrust(R-1)
        #登りながら関数 f を合成
        while L < R:
            if R & 1:
                R -= 1
                self.laz[R] = self.compose(self.laz[R],f)
            if L & 1:
                self.laz[L] = self.compose(self.laz[L],f)
                L += 1
            L >>= 1; R >>= 1
    
    # values[k] を取得。
    def point_get(self, k):
        res = self.val[k]
        k += self.N0
        while k:
            res = self.funcval(res, self.laz[k])
            k //= 2
        return res
    
    # values[k] = x 代入する
    def point_set(self, k): 
        self.thrust(k)
        values[k] = x



###########################################################################
#日経2020予選D

###########################################################################

# coding: utf-8
# Your code here!
 
import sys
sys.setrecursionlimit(10**6)
readline = sys.stdin.readline 

n,m = [int(i) for i in readline().split()]
lrc = [tuple(int(i) for i in readline().split()) for _ in range(m)]
lrc.sort()

compose = lambda f,g: min(f,g)
funcval = lambda x,f: min(x,f)
UNIT = INF = 10**18

seg = segment_tree(n, compose, funcval, UNIT)
seg.build([0]+[INF]*(n-1))

for l,r,c in lrc:
    l -= 1
    r -= 1
    v = seg.point_get(l)
    seg.update(l+1,r,v+c)

ans = seg.point_get(n-1)

if ans != INF:
    print(ans)
else:
    print(-1)

Submission status: Accepted

Solution code:
from heapq import heapify, heappush, heappop
import sys
input = sys.stdin.readline

INF = float('inf')

def solve():
    N, M = map(int, input().split())
    Es = []
    for _ in range(M):
        L, R, C = map(int, input().split())
        L, R = L-1, R-1
        Es.append((L, R, C))

    Es.sort()

    PQ = [(0, 0)]

    dists = [INF] * N
    iE = 0
    for tm in range(N):
        while PQ:
            dist, R = PQ[0]
            if tm <= R:
                break
            heappop(PQ)
        else:
            return -1

        dists[tm] = dist
        while iE < M and Es[iE][0] == tm:
            L, R, C = Es[iE]
            heappush(PQ, (dist+C, R))
            iE += 1

    return dists[-1]


print(solve())

Submission status: Accepted

Solution code:
from heapq import heappush, heappop

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

edges = [[] for _ in range(N)]
for i in range(1, N):
    edges[i].append((i - 1, 0))

for _ in range(M):
    l, r, c = map(int, input().split())
    l -= 1
    r -= 1
    edges[l].append((r, c))

que = [(0, 0)]
minDist = [float('inf')] * N
while que:
    d, now = heappop(que)
    if d >= minDist[now]:
        continue
    minDist[now] = d
    for to, cost in edges[now]:
        dist = d + cost
        if minDist[to] > dist:
            heappush(que, (dist, to))

ans = minDist[N - 1]
print(-1 if ans == float('inf') else ans)

Submission status: Accepted

Solution code:
import sys
from collections import defaultdict as dd
import heapq
input = sys.stdin.readline
N, M = map(int, input().split())
a = []
e = dd(list)
s = []
for _ in range(M):
  a.append(list(map(int, input().split())))
  e[a[-1][0]].append((a[-1][1], a[-1][2]))
a.sort(key = lambda x: (x[0], x[1]))
x = 0
for i in range(1, N):
  e[i + 1].append((i, 0))
class dijkstra:
  def __init__(self, n, e):
    self.e = e
    self.n = n
  def path(self, s, t):
    d = [float("inf")] * (self.n + 1)
    vis = set()
    d[s] = 0
    h = [s]
    while not t in vis and len(h):
      v = heapq.heappop(h)
      v1 = v % (10 ** 10)
      v0 = v // (10 ** 10)
      if v1 in vis: continue
      vis.add(v1)
      for p in self.e[v1]:
        d[p[0]] = min(d[p[0]], d[v1] + p[1])
        if p[0] in vis: continue
        heapq.heappush(h, d[p[0]] * (10 ** 10) + p[0])
    return d[t]
d = dijkstra(N, e)
res = d.path(1, N)
if res == float("inf"): print(-1)
else: print(res)

Submission status: Accepted

Solution code:
N,M = map(int,input().split(' '))
tree_list = [[] for _ in range(N) ]
for _ in range(M):
    L,R,C = map(int,input().split(' '))
    tree_list[R-1].append([C,L-1])
inf = float('inf')
dp = [inf] * N
dp[N-1] = 0
current_num = -1
flag = False
if len(tree_list[N-1]) > 0: 
    for i in reversed(range(N)):
        if dp[i] == inf:
            flag = True
            break
        current_start_paths = tree_list[i]
        if len(current_start_paths) > 0:
            current_start_paths.sort()
            for path in current_start_paths:
                if dp[path[1]] > dp[i] + path[0]:
                    for j in range(path[1],i):
                        if (dp[i] + path[0]) < dp[j]:
                            dp[j] = dp[i] + path[0]
                        else:
                            break
    if dp[0] == inf or flag:
        print(-1)
    else:
        print(dp[0])
else:
    print(-1)