Submission #1298264

#TimeUsernameProblemLanguageResultExecution timeMemory
1298264buzdiBitaro’s Party (JOI18_bitaro)C++17
14 / 100
508 ms261320 KiB
#include <bits/stdc++.h>
using namespace std;
using pii = pair<int,int>;
using ll = long long;

const int NMAX = 100000;
const int BSIZE = 316;

int n, m, q;
int v[NMAX + 5];
int dp[NMAX + 5];
vector<int> g[NMAX + 5], gt[NMAX + 5];
pii best[NMAX + 5][BSIZE + 2];

// temporaries for combine
static pii tmp_arr[2 * BSIZE + 5];
static pii out_arr[BSIZE + 2];

// timestamp trick to avoid unordered_set and clearing costs
static int seen_node[NMAX + 5];
static int seen_stamp = 1;

int solve_heavy(int t, int k) {
    // standard DP over incoming edges
    for(int i = 1; i <= t; ++i) dp[i] = 0;
    for(int i = 1; i <= k; ++i) dp[v[i]] = -1;
    for(int i = 1; i <= t; ++i) {
        for(int j : gt[i]) {
            if(dp[j] != -1) dp[i] = max(dp[i], dp[j] + 1);
        }
    }
    return dp[t];
}

int solve_light(int t, int k) {
    // use stamp array instead of unordered_set
    ++seen_stamp;
    if(seen_stamp == 0) { // wrap-around safety
        memset(seen_node, 0, sizeof(seen_node));
        seen_stamp = 1;
    }
    for(int i = 1; i <= k; ++i) seen_node[v[i]] = seen_stamp;

    for(int i = 1; i <= BSIZE; ++i) {
        if(best[t][i].first == -1) break;
        if(seen_node[best[t][i].second] != seen_stamp) return best[t][i].first;
    }
    return -1;
}

inline void combine(pii a[], pii b[]) {
    int i = 1, j = 1, ind = 0;
    // merge-like combine, but b's value is shifted by +1 in first
    while(i <= BSIZE && j <= BSIZE) {
        if(b[j].first == -1) {
            ++j; continue;
        }
        if(a[i].first == -1) {
            // all remaining a are -1, just take shifted b's
            tmp_arr[++ind] = {b[j].first + 1, b[j].second}; ++j; continue;
        }
        if(a[i].first > b[j].first + 1) {
            tmp_arr[++ind] = a[i++];
        } else {
            tmp_arr[++ind] = {b[j].first + 1, b[j].second}; ++j;
        }
    }
    while(i <= BSIZE) {
        if(a[i].first == -1) break;
        tmp_arr[++ind] = a[i++];
    }
    while(j <= BSIZE) {
        if(b[j].first == -1) { ++j; continue; }
        tmp_arr[++ind] = {b[j].first + 1, b[j].second}; ++j;
    }

    // deduplicate preserving order using seen_node + stamp
    ++seen_stamp;
    if(seen_stamp == 0) { // wrap-around safety
        memset(seen_node, 0, sizeof(seen_node));
        seen_stamp = 1;
    }
    int outc = 0;
    for(int k = 1; k <= ind && outc < BSIZE; ++k) {
        int node = tmp_arr[k].second;
        if(seen_node[node] != seen_stamp) {
            seen_node[node] = seen_stamp;
            out_arr[++outc] = tmp_arr[k];
        }
    }
    // write back to a[]
    for(int p = 1; p <= BSIZE; ++p) {
        if(p <= outc) a[p] = out_arr[p];
        else a[p] = make_pair(-1, 0);
    }
}

void precompute() {
    // initialize best arrays
    for(int i = 1; i <= n; ++i) {
        for(int j = 1; j <= BSIZE; ++j) best[i][j] = make_pair(-1, 0);
        best[i][1] = {0, i};
    }
    // combine for each incoming neighbor
    for(int i = 1; i <= n; ++i) {
        for(int j : gt[i]) {
            combine(best[i], best[j]);
        }
    }
}

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

    cin >> n >> m >> q;
    for(int i = 0; i < m; ++i) {
        int a,b; cin >> a >> b;
        g[a].push_back(b);
        gt[b].push_back(a);
    }

    precompute();

    while(q--) {
        int t,k; cin >> t >> k;
        for(int i = 1; i <= k; ++i) cin >> v[i];
        if(k > BSIZE) cout << solve_heavy(t,k) << '\n';
        else cout << solve_light(t,k) << '\n';
    }
    return 0;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...