제출 #1345379

#제출 시각아이디문제언어결과실행 시간메모리
1345379alexddBoard Game (JOI24_boardgame)C++20
3 / 100
4102 ms287344 KiB
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int INF = 1e18;
int n,m,k;
vector<int> con[50005];
bool iss[50005];
int init[50005];
int rez[50005];

int dist1[50005];
void calc_closest1()
{
    deque<int> dq;
    for(int i=1;i<=n;i++)
    {
        if(iss[i])
        {
            dist1[i] = 0;
            dq.push_back(i);
        }
        else
        {
            dist1[i] = INF;
        }
    }
    while(!dq.empty())
    {
        int nod = dq.front();
        dq.pop_front();

        for(int adj:con[nod])
        {
            if(dist1[adj] > dist1[nod] + 1)
            {
                dist1[adj] = dist1[nod] + 1;
                dq.push_back(adj);
            }
        }
    }
}

int best11[50005];
void calc_11()
{
    deque<int> dq;
    for(int i=1;i<=n;i++)
    {
        best11[i] = INF;
        if(!iss[i])
            continue;
        bool bun = 0;
        for(int adj:con[i])
            if(iss[adj])
                bun = 1;
        if(bun)
        {
            best11[i] = -1;
            dq.push_back(i);
        }
    }
    while(!dq.empty())
    {
        int nod = dq.front();
        dq.pop_front();
        for(int adj:con[nod])
        {
            if(iss[adj])
            {
                if(best11[adj] > best11[nod])
                {
                    best11[adj] = best11[nod];
                    dq.push_front(adj);
                }
            }
            else
            {
                if(best11[adj] > best11[nod] + 1)
                {
                    best11[adj] = best11[nod] + 1;
                    dq.push_back(adj);
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
        if(iss[i] && best11[i] < INF)
            best11[i]++;
}

int direct[50005];
void calc_directly()//see if we can reach some nodes without going through stop nodes
{
    deque<int> dq;
    for(int i=1;i<=n;i++)
        direct[i] = INF;
    direct[init[1]] = 0;
    dq.push_back(init[1]);
    while(!dq.empty())
    {
        int nod = dq.front();
        dq.pop_front();

        for(int adj:con[nod])
        {
            if(!iss[adj] && direct[adj] > direct[nod] + 1)
            {
                direct[adj] = direct[nod] + 1;
                dq.push_back(adj);
            }
        }
    }
    for(int i=1;i<=n;i++)
        for(int adj:con[i])
            rez[adj] = min(rez[adj], direct[i] + 1);

    for(int i=1;i<=n;i++)
        rez[i] = min(rez[i], direct[i]);
}

int dist[50005];
void calc_dist(int cost_first, int stop_cost)//optimize with 2 queues instead of a pq-------------------------------------------
{
    for(int i=1;i<=n;i++)
        dist[i] = INF;

    for(int i=1;i<=n;i++)
    {
        if(direct[i] == INF)
            continue;
        for(int adj:con[i])
        {
            if(iss[adj])
            {
                dist[adj] = min(dist[adj], cost_first + (direct[i] + 1));
            }
        }
    }

    deque<int> dq, dq2;
    for(int i=1;i<=n;i++)
        if(dist[i] < INF)
            dq.push_back(i);
    while(!dq.empty() || !dq2.empty())
    {
        int nod = -1;
        if(!dq.empty() && (dq2.empty() || dist[dq.front()] <= dist[dq2.front()]))
        {
            nod = dq.front();
            dq.pop_front();
        }
        else
        {
            assert(!dq2.empty());
            nod = dq2.front();
            dq2.pop_front();
        }

        for(int adj:con[nod])
        {
            if(iss[adj])
            {
                rez[adj] = min(rez[adj], dist[nod] + 1);

                if(dist[adj] > dist[nod] + stop_cost)
                {
                    dist[adj] = dist[nod] + stop_cost;
                    dq2.push_back(adj);
                }
            }
            else
            {
                if(dist[adj] > dist[nod] + 1)
                {
                    dist[adj] = dist[nod] + 1;
                    dq.push_back(adj);
                }
            }
        }
    }
    for(int i=1;i<=n;i++)
        rez[i] = min(rez[i], dist[i]);
}

void solve_small_k()
{


    //for(int i=1;i<=n;i++) cerr<<i<<": "<<dist1[i]<<" "<<best11[i]<<" dist1 & best11\n";

    //fix the nr of people that use 11------------------------------------
    vector<pair<int,int>> ord;
    for(int i=2;i<=k;i++)
    {
        ord.push_back({best11[init[i]] - dist1[init[i]], init[i]});
    }
    sort(ord.begin(), ord.end());


    for(int nr11=0;nr11<=k-1;nr11++)
    {
        int cost_first = 0, stop_cost = 1;
        bool good = 1;
        for(int i=0;i<nr11;i++)//take these as 11
        {
            int x = ord[i].second;
            if(best11[x] == INF)
            {
                good = 0;
                break;
            }
            cost_first += best11[x] + 1;
            stop_cost += 1;
        }
        for(int i=nr11;i<ord.size();i++)//take these as 1
        {
            int x = ord[i].second;
            if(dist1[x] == INF)
            {
                good = 0;
                break;
            }
            cost_first += dist1[x];
            stop_cost += 2;
        }
        if(good)
        {
            //cerr<<cost_first<<" "<<stop_cost<<" costs\n";
            calc_dist(cost_first, stop_cost);
        }
    }
}

int min1[50005];
void calc_min1()
{
    deque<int> dq;
    for(int i=1;i<=n;i++)
        min1[i] = INF;
    min1[init[1]] = 0;
    dq.push_back(init[1]);
    while(!dq.empty())
    {
        int nod = dq.front();
        dq.pop_front();
        for(int adj:con[nod])
        {
            if(iss[adj])
            {
                if(min1[adj] > min1[nod] + 1)
                {
                    min1[adj] = min1[nod] + 1;
                    dq.push_back(adj);
                }
            }
            else
            {
                if(min1[adj] > min1[nod])
                {
                    min1[adj] = min1[nod];
                    dq.push_front(adj);
                }
            }
        }
    }
}
map<int,int> dp[50005];
void solve_big_k()
{
    int DIF = m / k + 5;

    priority_queue<pair<int,pair<int,int>>> pq;
    dp[init[1]][0] = -INF;
    pq.push({-dp[init[1]][0], {init[1], 0}});
    while(!pq.empty())
    {
        int nod = pq.top().second.first;
        int cnt1 = pq.top().second.second;
        int cdp = -pq.top().first;
        pq.pop();
        if(cdp != dp[nod][cnt1])
            continue;
        for(int adj:con[nod])
        {
            if(dp[adj][cnt1 + iss[adj]] > cdp + 1 && (cnt1 + iss[adj]) <= min1[adj] + DIF)
            {
                dp[adj][cnt1 + iss[adj]] = cdp + 1;
                pq.push({-dp[adj][cnt1 + iss[adj]], {adj, cnt1 + iss[adj]}});
            }
        }
    }
    vector<int> f(n+2, INF);
    for(int x=1;x<=n;x++)
    {
        f[x] = 0;
        for(int i=2;i<=k;i++)
        {
            f[x] += min(dist1[init[i]] + (x-1) * 2, best11[init[i]] + x);
        }
    }
    for(int i=1;i<=n;i++)
    {
        for(auto it:dp[i])
        {
            int cnt1 = it.first;
            int mydp = it.second + INF;

            if(iss[i])
                cnt1--;

            if(1 <= cnt1 && cnt1 <= n) rez[i] = min(rez[i], mydp + f[cnt1]);
        }
    }
}

signed main()
{
    ios_base::sync_with_stdio(0);cin.tie(0);
    cin>>n>>m>>k;
    int u,v;
    for(int i=1;i<=m;i++)
    {
        cin>>u>>v;
        con[u].push_back(v);
        con[v].push_back(u);
    }
    string s;
    cin>>s;
    assert(s.size() == n);
    for(int i=0;i<s.size();i++)
    {
        if(s[i] == '1')
            iss[i+1] = 1;
        else
            iss[i+1] = 0;
    }
    for(int i=1;i<=k;i++)
        cin>>init[i];

    for(int i=1;i<=n;i++)
        rez[i] = INF;

    calc_directly();

    calc_11();
    calc_closest1();

    for(int i=1;i<=n;i++)
        if(dist1[i] == 0)
            dist1[i] = 2;

    if(k <= 500 && 0)
    {
        solve_small_k();
    }
    else
    {
        solve_big_k();
    }

    for(int i=1;i<=n;i++)
    {
        assert(rez[i] < INF);
        cout<<rez[i]<<"\n";
    }

    return 0;
}
#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...