제출 #645398

#제출 시각아이디문제언어결과실행 시간메모리
645398alvinpiterBitaro’s Party (JOI18_bitaro)C++17
7 / 100
1638 ms524292 KiB
/*
2018 JOI Spring Training Camp/Qualifying Trial Day 3

There are two ways to solve this problem, and we need to combine them:
* In O(N), by using dynamic programming. dp[i] -> maximum number of jumps to reach destination from node i.
* (N + M)*THRESHOLD, by precomputation. For each node, we store the top THRESHOLD furthest nodes from it.

We solve the problem with the first approach whenever the Y is >= THRESHOLD. When doing so, the total complexity
for answering all queries will be (N/THRESHOLD)*N. By choosing THRESHOLD to be sqrt(N), the complexity is N*sqrt(N).

If Y < THRESHOLD, then we can use our precomputed value since we store the top THRESHOLD nodes from each node. Which means
at least one of them is able to attend the party.
*/

#include<bits/stdc++.h>
using namespace std;
#define MAXN 100000
#define THRESHOLD 320

int N, M, Q, T, Y, C[MAXN + 3], canGo[MAXN + 3], dp[MAXN + 3];
vector<int> nxt[MAXN + 3];
vector<pair<int, int> > best[MAXN + 3]; // best[u] -> [ {numJump, who} ], means we can reach "u" from "who" with "numJump" jumps.

int main() {
  cin >> N >> M >> Q;
  for (int i = 1; i <= M; i++) {
    int s, e;
    cin >> s >> e;

    nxt[s].push_back(e);
  }

  for (int i = 1; i <= N; i++) {
    canGo[i] = true;
  }

  for (int i = 1; i <= N; i++) {
    best[i].push_back({0, i});
  }

  for (int i = 1; i <= N; i++) {
    sort(best[i].rbegin(), best[i].rend());
    for (int j = 0; j < min((int) best[i].size(), THRESHOLD); j++) {
      int numJump = best[i][j].first, who = best[i][j].second;
      for (auto k: nxt[i]) {
        best[k].push_back({numJump + 1, who});
      }
    }
  }

  for (int q = 1; q <= Q; q++) {
    cin >> T >> Y;
    for (int i = 1; i <= Y; i++) {
      cin >> C[i];
      canGo[C[i]] = false;
    }

    if (Y >= THRESHOLD) {
      dp[T] = 0;
      for (int i = T - 1; i >= 1; i--) {
        dp[i] = -1;
        for (auto j: nxt[i]) {
          if (j <= T && dp[j] != -1) {
            dp[i] = max(dp[i], 1 + dp[j]);
          }
        }
      }

      int ans = -1;
      for (int i = 1; i <= T; i++) {
        if (canGo[i] && dp[i] != -1) {
          ans = max(ans, dp[i]);
        }
      }

      cout << ans << endl;
    } else {
      int ans = -1;
      for (auto [numJump, who]: best[T]) {
        if (canGo[who]) {
          ans = max(ans, numJump);
        }
      }

      cout << ans << endl;
    }

    // Reset
    for (int i = 1; i <= Y; i++) {
      canGo[C[i]] = true;
    }
  }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...