제출 #985560

#제출 시각아이디문제언어결과실행 시간메모리
985560maomao90Board Game (JOI24_boardgame)C++17
100 / 100
2487 ms93900 KiB

// Hallelujah, praise the one who set me free
// Hallelujah, death has lost its grip on me
// You have broken every chain, There's salvation in your name
// Jesus Christ, my living hope
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <utility>
#include <numeric>
#include <bitset>
#include <map>
#include <queue>
#include <cassert>
using namespace std;

#define REP(i, s, e) for (int i = (s); i < (e); i++)
#define RREP(i, s, e) for (int i = (s); i >= (e); i--)
template <class T>
inline bool mnto(T& a, T b) {return a > b ? a = b, 1 : 0;}
template <class T>
inline bool mxto(T& a, T b) {return a < b ? a = b, 1: 0;}

typedef unsigned long long ull;
typedef long long ll;
typedef long double ld;
#define FI first
#define SE second
typedef pair<int, int> ii;
typedef pair<ll, ll> pll;
typedef tuple<int, int, int> iii;
typedef tuple<ll, ll, ll> lll;
#define ALL(_a) _a.begin(), _a.end()
#define SZ(_a) (int) _a.size()
#define pb push_back
typedef vector<int> vi;
typedef vector<ll> vll;
typedef vector<ii> vii;
typedef vector<iii> viii;

#ifndef DEBUG
#define cerr if (0) cerr
#endif

const int INF = 1000000005;
const ll LINF = 1000000000000000005ll;
const int MAXN = 50005;
const int BLK = 300;
//const int MAXN = 50;
//const int BLK = 1;

int n, m, k;
vi adj[MAXN];
string s;
int x[MAXN];

namespace SmallKSolver {
    ll base[MAXN], delta[MAXN];
    int rawd[MAXN], goodd[MAXN];
    ll d[2][MAXN];
    queue<int> qu;
    deque<int> dq;
    priority_queue<lll, vector<lll>, greater<lll>> pq;
    bool fix[MAXN];
    ll ans[MAXN];
    int main() {
        // distance to closest stop
        REP (i, 0, n) {
            rawd[i] = INF;
        }
        REP (i, 0, n) {
            if (s[i] == '1') {
                qu.push(i);
                rawd[i] = 0;
            }
        }
        while (!qu.empty()) {
            int u = qu.front(); qu.pop();
            for (int v : adj[u]) {
                if (mnto(rawd[v], rawd[u] + 1)) {
                    qu.push(v);
                }
            }
        }
        REP (i, 0, n) {
            if (rawd[i] == 0) {
                rawd[i] = 2;
            }
        }
        REP (i, 1, k) {
            base[0] += rawd[x[i]];
        }
        // "good" vertex is stop cell and has adjacent stop cell
        // distance to closest "good" vertex
        REP (i, 0, n) {
            goodd[i] = INF;
        }
        REP (i, 0, n) {
            if (s[i] == '0') {
                continue;
            }
            bool gd = 0;
            for (int v : adj[i]) {
                if (s[v] == '1') {
                    gd = 1;
                    break;
                }
            }
            if (gd) {
                goodd[i] = 0;
                dq.push_back(i);
            }
        }
        while (!dq.empty()) {
            int u = dq.front(); dq.pop_front();
            for (int v : adj[u]) {
                if (mnto(goodd[v], goodd[u] + (s[u] == '0'))) {
                    if (s[u] == '0') {
                        dq.push_back(v);
                    } else {
                        dq.push_front(v);
                    }
                }
            }
        }
        REP (i, 1, k) {
            delta[i - 1] = goodd[x[i]] - rawd[x[i]];
        }
        sort(delta, delta + k - 1);
        cerr << base[0] << '\n';
        REP (i, 1, k) {
            base[i] = base[i - 1] + delta[i - 1];
            cerr << i << ": " << delta[i - 1] << ' ' << base[i] << '\n';
        }
        // get answer without stop cells
        REP (i, 0, n) {
            ans[i] = LINF;
        }
        ans[x[0]] = 0;
        qu.push(x[0]);
        while (!qu.empty()) {
            int u = qu.front(); qu.pop();
            for (int v : adj[u]) {
                if (mnto(ans[v], ans[u] + 1) && s[v] == '0') {
                    qu.push(v);
                }
            }
        }
        REP (i, 0, n) {
            fix[i] = ans[i] != LINF;
        }
        REP (g, 0, k) {
            cerr << g << '\n';
            REP (i, 0, n) {
                d[0][i] = d[1][i] = LINF;
            }
            d[0][x[0]] = 0;
            pq.push({0, x[0], 0});
            while (!pq.empty()) {
                auto [ud, u, t] = pq.top(); pq.pop();
                if (d[t][u] != ud) {
                    continue;
                }
                for (int v : adj[u]) {
                    bool b = u != x[0] && s[u] == '1';
                    if (mnto(d[b | t][v], ud + (b ? 2 * k - 1 - g : 1))) {
                        pq.push({d[b | t][v], v, b | t});
                    }
                }
            }
            REP (i, 0, n) {
                mnto(ans[i], d[1][i] + base[g] - 2 * (k - 1 - g));
                cerr << ' ' << i << ": " << d[i] << ' ' << ans[i] << '\n';
            }
        }
        REP (i, 0, n) {
            cout << ans[i] << '\n';
        }
        return 0;
    }
}

namespace BigKSolver {
    ll delta[MAXN], cost[MAXN];
    int rawd[MAXN], goodd[MAXN];
    queue<int> qu;
    deque<int> dq;
    priority_queue<lll, vector<lll>, greater<lll>> pq;
    int mnl[MAXN];
    ll d[MAXN][MAXN / BLK + 50];
    ll ans[MAXN];
    int main() {
        int MAXL = n / (k - 1) + 10;
        // distance to closest stop
        REP (i, 0, n) {
            rawd[i] = INF;
        }
        REP (i, 0, n) {
            if (s[i] == '1') {
                qu.push(i);
                rawd[i] = 0;
            }
        }
        while (!qu.empty()) {
            int u = qu.front(); qu.pop();
            for (int v : adj[u]) {
                if (mnto(rawd[v], rawd[u] + 1)) {
                    qu.push(v);
                }
            }
        }
        // "good" vertex is stop cell and has adjacent stop cell
        // distance to closest "good" vertex
        REP (i, 0, n) {
            goodd[i] = INF;
        }
        REP (i, 0, n) {
            if (s[i] == '0') {
                continue;
            }
            bool gd = 0;
            for (int v : adj[i]) {
                if (s[v] == '1') {
                    gd = 1;
                    break;
                }
            }
            if (gd) {
                goodd[i] = 0;
                dq.push_back(i);
            }
        }
        while (!dq.empty()) {
            int u = dq.front(); dq.pop_front();
            for (int v : adj[u]) {
                if (mnto(goodd[v], goodd[u] + (s[v] == '0'))) {
                    if (s[v] == '0') {
                        dq.push_back(v);
                    } else {
                        dq.push_front(v);
                    }
                }
            }
        }
        REP (i, 0, n) {
            goodd[i] += s[i] == '1';
        }
        REP (i, 0, n) {
            if (rawd[i] == 0) {
                rawd[i] = min(goodd[i], 2);
            }
        }
        ll base = 0;
        REP (i, 1, k) {
            base += rawd[x[i]];
        }
        REP (i, 1, k) {
            delta[i - 1] = goodd[x[i]] - rawd[x[i]];
            cerr << delta[i - 1] << "\n";
        }
        sort(delta, delta + k - 1);
        cost[1] = base;
        int ptr = 0;
        REP (i, 2, n + 1) {
            while (ptr < k - 1 && delta[ptr] <= i - 2) {
                ptr++;
            }
            cost[i] = cost[i - 1] + 2 * (k - 1) - ptr;
            cerr << i << ": " << cost[i] << "\n";
        }

        REP (i, 0, n) {
            mnl[i] = INF;
        }
        mnl[x[0]] = 0;
        dq.pb(x[0]);
        while (!dq.empty()) {
            int u = dq.front(); dq.pop_front();
            for (int v : adj[u]) {
                bool b = u != x[0] && s[u] == '1';
                if (mnto(mnl[v], mnl[u] + b)) {
                    if (b) {
                        dq.push_back(v);
                    } else {
                        dq.push_front(v);
                    }
                }
            }
        }

        REP (i, 0, n) {
            ans[i] = LINF;
            REP (j, 0, MAXL) {
                d[i][j] = LINF;
            }
        }
        d[x[0]][0] = 0;
        pq.push({0, x[0], 0});
        while (!pq.empty()) {
            auto [ud, u, l] = pq.top(); pq.pop();
            if (ud != d[u][l - mnl[u]]) {
                continue;
            }
            for (int v : adj[u]) {
                bool b = u != x[0] && s[u] == '1';
                if (l + b - mnl[v] < MAXL && mnto(d[v][l + b - mnl[v]], ud + 1)) {
                    pq.push({d[v][l + b - mnl[v]], v, l + b});
                }
            }
        }

        REP (i, 0, n) {
            REP (j, 0, min(MAXL, n - mnl[i] + 1)) {
                mnto(ans[i], d[i][j] + cost[j + mnl[i]]);
            }
        }

        REP (i, 0, n) {
            cout << ans[i] << '\n';
        }
        return 0;
    }
}

int main() {
#ifndef DEBUG
    ios::sync_with_stdio(0), cin.tie(0);
#endif
    cin >> n >> m >> k;
    REP (i, 0, m) {
        int u, v; cin >> u >> v;
        u--; v--;
        adj[u].pb(v);
        adj[v].pb(u);
    }
    cin >> s;
    REP (i, 0, k) {
        cin >> x[i];
        x[i]--;
    }
    if (k <= BLK) {
        return SmallKSolver::main();
    } else {
        return BigKSolver::main();
    }
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...