Submission #1288654

#TimeUsernameProblemLanguageResultExecution timeMemory
1288654c4lBitaro’s Party (JOI18_bitaro)C++20
100 / 100
1950 ms199796 KiB
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>;
const int NEG_INF = -1000000000;

// TUNABLE: kích thước bucket (trade-off tiền xử lý <-> trả lời truy vấn nhỏ)
// Bạn có thể thử 180..300; mình đặt 200 để an toàn về bộ nhớ.
const int B = 200;

int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    int N, M, Q;
    if(!(cin >> N >> M >> Q)) return 0;

    vector<vector<int>> rev_adj(N+1); // rev_adj[v] chứa các u sao cho u -> v (u < v)
    vector<vector<int>> out_adj(N+1); // out_adj[u] chứa các v sao cho u -> v (v > u)
    for(int i=0;i<M;i++){
        int s,e; cin >> s >> e;
        // theo đề: kênh chạy từ cao xuống thấp, chỉ số nhỏ -> lớn
        // tổng quát: có cung s->e
        out_adj[s].push_back(e);
        rev_adj[e].push_back(s);
    }

    // dp[v]: tối đa giữ B cặp (len, src) nghĩa là "từ src -> v có đường dài = len"
    vector<vector<pii>> dp(N+1);
    vector<int> seen(N+1, 0);
    int seenTime = 1;

    // Xây dp tăng dần v = 1..N
    for(int v = 1; v <= N; ++v){
        // thu thập các ứng viên: (0, v) + từ mỗi w trước v (w->v) lấy dp[w] + 1
        vector<pii> cand;
        cand.reserve(1 + (int)rev_adj[v].size() * B);
        cand.emplace_back(0, v);
        for(int w : rev_adj[v]){
            for(auto &p : dp[w]){
                cand.emplace_back(p.first + 1, p.second);
            }
        }
        // sắp xếp giảm dần theo length (nếu bằng thì theo node nhỏ)
        sort(cand.begin(), cand.end(), [](const pii &a, const pii &b){
            if(a.first != b.first) return a.first > b.first;
            return a.second < b.second;
        });
        // chọn top B với đỉnh nguồn duy nhất
        vector<pii> out;
        out.reserve(min((int)cand.size(), B));
        ++seenTime;
        for(auto &p : cand){
            if((int)out.size() >= B) break;
            int node = p.second;
            if(seen[node] == seenTime) continue;
            seen[node] = seenTime;
            out.push_back(p);
        }
        dp[v].swap(out);
    }

    vector<int> forbidden(N+1, 0);
    int curMark = 1;
    vector<int> best(N+2, NEG_INF);

    // xử lý Q truy vấn
    for(int qi = 0; qi < Q; ++qi){
        int T, Y;
        cin >> T >> Y;
        vector<int> forb(Y);
        for(int i=0;i<Y;i++) cin >> forb[i];

        if(Y < B){
            // trường hợp nhỏ: đánh dấu các forb và quét dp[T]
            ++curMark;
            for(int x : forb) if(1 <= x && x <= N) forbidden[x] = curMark;
            int ans = -1;
            for(auto &p : dp[T]){
                int len = p.first;
                int src = p.second;
                if(forbidden[src] == curMark) continue; // nguồn bị cấm
                ans = len;
                break;
            }
            cout << ans << '\n';
        } else {
            // trường hợp lớn: chạy DP từ T trên prefix 1..T (không loại nút trung gian)
            // best[i] = max length from i -> T (or NEG_INF nếu ko tới được)
            for(int i = 1; i <= T; ++i) best[i] = NEG_INF;
            best[T] = 0;
            // duyệt i từ T-1..1 (cũng có thể từ T downto 1), vì các cạnh i->v có v>i
            for(int i = T; i >= 1; --i){
                // nếu i == T thì best[T] đã = 0; nhưng vẫn duyệt ra
                for(int v : out_adj[i]){
                    if(v > T) continue; // ngoài prefix T
                    if(best[v] != NEG_INF){
                        best[i] = max(best[i], best[v] + 1);
                    }
                }
            }
            // đánh dấu forbidden (chỉ dùng để loại nguồn khi lấy max)
            ++curMark;
            for(int x : forb) if(1 <= x && x <= N) forbidden[x] = curMark;
            int ans = -1;
            for(int i = 1; i <= T; ++i){
                if(best[i] == NEG_INF) continue;
                if(forbidden[i] == curMark) continue; // nguồn bị cấm
                ans = max(ans, best[i]);
            }
            cout << ans << '\n';
        }
    }

    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...