제출 #1370563

#제출 시각아이디문제언어결과실행 시간메모리
1370563yogesh_sane봉쇄 시간 (IOI23_closing)C++20
43 / 100
88 ms45372 KiB
#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define pll pair<ll,ll>
#define f first
#define s second
#define pb push_back
#define all(x) x.begin(),x.end()

const int mxn = 2e5+5;
vector<pll> g[mxn];
ll d[2][mxn]{0};
int lvl[mxn]{0};
int core[mxn]{0};
multiset<pll> ms;

// Standard DFS to calculate distances from a source node
void dfs(int i, int u, int p) {
    for(auto [v, w] : g[u]) {
        if(v == p) continue;
        d[i][v] = d[i][u] + w;
        dfs(i, v, u);
    }
}

// Resets global arrays for multiple test cases
void clean(int n) {
    for(int i = 0; i < n; i++) {
        g[i].clear();
        d[0][i] = d[1][i] = lvl[i] = core[i] = 0;
    }
}

int max_score(int N, int X, int Y, ll K, vector<int> U, vector<int> V, vector<int> W) {
    // Build the adjacency list
    for(int i = 0; i < N - 1; i++) {
        g[U[i]].pb({(ll)V[i], (ll)W[i]});
        g[V[i]].pb({(ll)U[i], (ll)W[i]});
    }

    // Calculate distances from both starting points X and Y
    dfs(0, X, X);
    dfs(1, Y, Y);

    // --- CASE 1: Independent Greedy ---
    // Nodes are treated as separate instances for X and Y.
    // We just pick the cheapest distances globally until K is exhausted.
    ll sum = 0;
    int rs1 = 0;
    priority_queue<ll, vector<ll>, greater<ll>> pq;
    for(int i = 0; i < N; i++) {
        pq.push(d[0][i]);
        pq.push(d[1][i]);
    }
    while(!pq.empty() && sum + pq.top() <= K) {
        sum += pq.top();
        rs1++;
        pq.pop();
    }

    // --- Prep for CASE 2: Overlapping Greedy ---
    // Normalize distances so d[0] is distance to nearest source, 
    // and d[1] is the incremental cost to reach the second level.
    for(int i = 0; i < N; i++) {
        if(d[0][i] > d[1][i]) swap(d[0][i], d[1][i]);
        d[1][i] -= d[0][i];
    }

    sum = 0;
    int rs2 = 0;
    ms.clear();
    ms.insert({0, -1}); // Sentinel
    priority_queue<pll, vector<pll>, greater<pll>> q1, q2;

    // Identify the "core" path between X and Y. These nodes MUST be visited.
    for(int i = 0; i < N; i++) {
        if(d[0][i] + d[1][i] + d[0][i] == d[1][X] + d[0][X]) { // Check if node is on the X-Y path
            sum += d[0][i];
            rs2++;
            lvl[i] = 1;
            q1.push({d[1][i], i + 1}); // Add incremental cost to reach level 2
            core[i] = 1;
        }
    }

    // Fill queues: q1 for 1-level gains, q2 for 2-level gains at once
    for(int i = 0; i < N; i++) {
        if(lvl[i] == 0) {
            q1.push({d[0][i], -(i + 1)});
            q2.push({d[0][i] + d[1][i], i + 1});
        }
    }

    if(sum > K) {
        clean(N);
        return rs1;
    }

    // Greedy selection with potential "backtracking" (using multiset ms)
    while(!q1.empty() || !q2.empty()) {
        // Handle cases where one queue is empty
        if(q2.empty()) {
            auto [x, i] = q1.top(); q1.pop();
            int lv = (i > 0); i = abs(i) - 1;
            if(lvl[i] > lv) continue;
            if(sum + x > K) { clean(N); return max(rs1, rs2); }
            sum += x; rs2++;
            if(lvl[i] == 0) { lvl[i] = 1; ms.insert({x, i}); q1.push({d[1][i], i + 1}); }
            else if(lvl[i] == 1) { lvl[i] = 2; if(!core[i]) ms.erase({d[0][i], i}); ms.insert({x, i}); }
        }
        else if(q1.empty()) {
            auto [x, i] = q2.top(); q2.pop(); i--;
            if(lvl[i] != 0) continue;
            if(sum + x > K) { clean(N); return max(rs1, rs2); }
            sum += x; rs2 += 2;
            lvl[i] = 2; ms.insert({d[1][i], i});
        }
        // Main greedy logic: compare taking one best node vs taking a pair/level-2 node and removing the most expensive current pick
        else if(q1.top().f <= q2.top().f - (--ms.end())->f) {
            auto [x, i] = q1.top(); q1.pop();
            int lv = (i > 0); i = abs(i) - 1;
            if(sum + x > K) { clean(N); return max(rs1, rs2); }
            sum += x; rs2++;
            if(lvl[i] == 0) { lvl[i] = 1; ms.insert({x, i}); q1.push({d[1][i], i + 1}); }
            else if(lvl[i] == 1) { lvl[i] = 2; if(!core[i]) ms.erase({d[0][i], i}); ms.insert({x, i}); }
        }
        else {
            // Replacement logic: take a 2-level jump and undo the least efficient previous move
            auto [x, i] = q2.top(); q2.pop(); i--;
            if(lvl[i] != 0) continue;
            if(sum + x - (--ms.end())->f > K) { clean(N); return max(rs1, rs2); }
            sum += x - (--ms.end())->f; rs2++;
            auto it = (--ms.end());
            // Update the state of the node we "undid" or downgraded
            if(lvl[it->s] == 1) {
                lvl[it->s] = 0;
                q1.push({d[0][it->s], -it->s - 1});
                q2.push({d[0][it->s] + d[1][it->s], it->s + 1});
                ms.erase(it);
            }
            else if(lvl[it->s] == 2) {
                lvl[it->s] = 1;
                q1.push({d[1][it->s], it->s + 1});
                if(!core[it->s]) ms.insert({d[0][it->s], it->s});
                ms.erase(it);
            }
            lvl[i] = 2; ms.insert({d[1][i], i});
        }
    }
    
    clean(N);
    return max(rs1, rs2);
}
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…
#결과 실행 시간메모리채점기 출력
결과를 불러오는 중입니다…