DOJ logoDOJ
문제
최근 추가된 문제들저장한 문제
카테고리DLC대회그룹팀게시판
랭킹
문제 풀이 랭킹스트릭 랭킹DOJ Power 랭킹
현황
문제 제안로그인회원가입
DOJ logoDOJ

OI 서브태스크 채점, Elo 레이팅, Discord 인증을 갖춘 커뮤니티 온라인 저지.

문제
문제 목록카테고리
커뮤니티
대회랭킹게시판공지사항외부 대회 개최이용 안내
계정
로그인회원가입채점 현황
정책
이용약관DLC 이용 규칙개인정보 처리방침API 사용 설명서언어별 채점 환경대회 순위 보상레이팅과 퍼포먼스
© 2026 DOJ
모든 권리 보유
해설

인터네셔널 OJ

문제로 돌아가기

해설

완료 시각 계산

서버 iii에 지금까지 들어온 마지막 제출의 완료 시각을 FiF_iFi​라고 하자. 시각 ttt에 채점 시간 yyy인 제출이 서버 iii에 들어오면 시작 시각과 완료 시각은

start=max⁡(t,Fi),finish=max⁡(t,Fi)+y\mathrm{start}=\max(t,F_i),\qquad \mathrm{finish}=\max(t,F_i)+ystart=max(t,Fi​),finish=

이다. 이후 FiF_iFi​를 새 완료 시각으로 갱신한다. 각 서버가 FIFO 순서로 제출을 처리하므로 실제 큐를 저장할 필요는 없다.

여러 서버가 동시에 동작하므로 제출 쿼리 순서와 실제 완료 순서는 다를 수 있다. 계산한 완료 시각을 기준으로 완료 이벤트를 최소 힙에 저장한다. 시각 ttt의 쿼리를 처리하기 전에 완료 시각이 ttt 이하인 이벤트를 모두 꺼내 데이터베이스와 랭킹 자료구조에 반영한다.

완료 시각은 입력의 ttt보다 훨씬 커질 수 있다. 한 서버에 채점 시간 10910^9109인 제출이 많이 쌓일 수 있으므로 완료 시각은 반드시 64비트 정수로 저장한다.

문제별 랭킹

한 제출의 문제 랭킹 비교 키는

(judgeTime, finishTime, submissionOrder)(\mathrm{judgeTime},\ \mathrm{finishTime},\ \mathrm{submissionOrder})(judgeTime, finishTime, submissionOrder)

이다.

각 문제에서 필요한 것은 상위 555개뿐이다. 따라서 문제마다 현재 상위 555개 기록만 정렬된 벡터로 유지한다. 새 완료 기록을 추가하고 정렬한 뒤 원소가 666개가 되면 가장 뒤의 원소를 제거한다.

한 번 상위 555개에서 밀려난 기록은 이후 더 많은 기록이 추가되더라도 다시 상위 555개에 들어올 수 없다. 새 기록의 추가는 기존 기록의 상대 순위를 개선하지 않기 때문이다. 따라서 문제 하나당 O(1)O(1)O(1)개의 기록만 저장하면 된다.

사용자 랭킹

사용자 uuu에 대해 다음 두 값을 저장한다.

  • CuC_uCu​: 현재 푼 문제 수.
  • AuA_uAu​: 현재의 푼 문제 수를 달성한 시각.

사용자 랭킹의 비교 키는

(−Cu, Au, nickname)(-C_u,\ A_u,\ \mathrm{nickname})(−Cu​, Au​, nickname)

이다. 이 키를 std::set에 저장하면 앞에서부터 랭킹 순서가 된다.

사용자가 새로운 문제를 처음 풀면 기존 키를 집합에서 삭제한다. 그 뒤 CuC_uCu​를 111 증가시키고 AuA_uAu​를 해당 제출의 완료 시각으로 바꾼 다음 새 키를 삽입한다.

같은 사용자가 같은 문제를 여러 번 제출해도 푼 문제 수는 한 번만 증가해야 한다. 완료된 (user,problem)(\mathrm{user},\mathrm{problem})(user,problem) 쌍을 해시 집합에 저장하고, 완료 이벤트를 처리할 때 그 쌍이 처음 등장한 경우에만 사용자 랭킹을 갱신한다. 중요한 점은 중복 여부를 제출 시점이 아니라 완료 시점에 판정해야 한다는 것이다. 나중에 제출된 같은 문제의 제출이 다른 서버에서 더 먼저 완료될 수 있기 때문이다.

문제별 랭킹에는 같은 사용자의 같은 문제 제출도 모두 서로 다른 기록으로 추가한다.

쿼리 처리

각 쿼리의 시각을 ttt라고 하자. 먼저 최소 힙에서 완료 시각이 ttt 이하인 이벤트를 모두 꺼내 처리한다.

  • 111번 쿼리에서는 서버별 마지막 완료 시각으로 새 제출의 완료 시각을 계산하고 완료 이벤트를 최소 힙에 넣는다.
  • 222번 쿼리에서는 해당 문제의 상위 555개 벡터를 순서대로 출력한다.
  • 333번 쿼리에서는 사용자 랭킹 집합의 앞에서 최대 555명을 출력한다.

서브태스크

서브태스크 1에서는 매 출력 쿼리마다 지금까지의 완료 제출을 다시 조사하고 정렬해도 된다. 총 QQQ가 2 0002\,0002000 이하이므로 O(Q2log⁡Q)O(Q^2\log Q)O(Q2logQ) 풀이가 충분하다.

서브태스크 2에서는 서버가 하나이고 333번 쿼리가 없다. 완료 순서가 제출 순서와 같으므로 완료 이벤트를 큐로 처리하고 문제별 상위 555개만 유지하면 된다.

서브태스크 3에서는 사용자 랭킹이 필요 없다. 여러 서버의 완료 이벤트를 최소 힙으로 처리하고 문제별 상위 555개만 유지하면 된다.

서브태스크 4에서는 서버가 하나이고 222번 쿼리가 없으며 모든 (nickname,problem)(\mathrm{nickname},\mathrm{problem})(nickname,problem) 쌍이 한 번만 제출된다. 완료 이벤트를 큐로 처리하며 사용자 랭킹 집합만 유지하면 된다.

서브태스크 5에서는 (nickname,problem)(\mathrm{nickname},\mathrm{problem})(nickname,problem) 쌍이 중복되지 않으므로 완료된 쌍을 검사하는 해시 집합이 필요 없다. 최소 힙, 문제별 상위 555개, 사용자 랭킹 집합을 함께 유지한다.

전체 제약에서는 여기에 완료된 (user,problem)(\mathrm{user},\mathrm{problem})(user,problem) 쌍의 해시 집합을 추가한다.

복잡도

각 제출은 완료 이벤트 최소 힙에 한 번 삽입되고 한 번 삭제된다. 사용자 랭킹의 삭제와 삽입은 각각 O(log⁡Q)O(\log Q)O(logQ)이고, 문제별 상위 555개 갱신은 O(1)O(1)O(1)이다.

한 테스트 케이스의 시간 복잡도는 O((N+Q)log⁡Q)O((N+Q)\log Q)O((N+Q)logQ)로 볼 수 있으며, 공간 복잡도는 O(N+Q)O(N+Q)O(N+Q)이다. 전체 입력에서는 ∑N,∑Q≤200 000\sum N,\sum Q\le 200\,000이므로 충분하다.

Solution written by GPT5.6

max(t,Fi​)+
y
∑
N
,
∑
Q
≤
200000