Submission #1223711

#TimeUsernameProblemLanguageResultExecution timeMemory
1223711LucaIlieClosing Time (IOI23_closing)C++17
100 / 100
215 ms59668 KiB

#include "closing.h"
#include <bits/stdc++.h>

using namespace std;

struct edge {
    int u, v, c;

    int other(int x) {
        return u ^ v ^ x;
    }
};

struct aaa {
    int t, v;
    long long c;

    bool operator < (const aaa &x) const {
        if (x.c == c)
            return x.t < t;
        return x.c < c;
    }
};

const int MAX_N = 2e5;
const long long INF = 1e18;
edge edges[MAX_N];
vector<int> adj[MAX_N];
int parent[MAX_N];
vector<int> path;
vector<int> subtree[MAX_N];
bool onPath[MAX_N];
int level[MAX_N];
long long dp[2 * MAX_N + 1];
long long distX[MAX_N], distY[MAX_N];
long long cost1[MAX_N], upgrade[MAX_N];
long long paid[MAX_N];

void calcDist(int u, int p, long long dist[]) {
    // printf("aa %d %d %lld\n", u, p, dist[u]);
    parent[u] = p;
    for (int e: adj[u]) {
        int v = edges[e].other(u), c = edges[e].c;
        if (v == p)
            continue;
        dist[v] = dist[u] + c;
        calcDist(v, u, dist);
    }
}

void findSubtree(int u, int p, int w) {
    subtree[w].push_back(u);
    for (int e: adj[u]) {
        int v = edges[e].other(u);
        if (v == p || onPath[v])
            continue;
        findSubtree(v, u, w);
    }
}

int max_score(int n, int x, int y, long long k, 
                vector<int> U, vector<int> V, vector<int> W) {

    for (int v = 0; v < n; v++) {
        adj[v].clear();
        subtree[v].clear();
        parent[v] = 0;
        distX[v] = distY[v] = 0;
        onPath[v] = false;
        path.clear();
    }
    for (int e = 0; e < n - 1; e++) {
        adj[U[e]].push_back(e);
        adj[V[e]].push_back(e);
        edges[e] = {U[e], V[e], W[e]};
    }

    calcDist(x, -1, distX);
    calcDist(y, -1, distY);

    int v = x;
    while (v != y) {
        path.push_back(v);
        onPath[v] = true;
        v = parent[v];
    }
    path.push_back(y);
    onPath[y] = true;
    int m = path.size();

    for (int v = 0; v < n; v++) {
        cost1[v] = min(distX[v], distY[v]);
        upgrade[v] = max(distX[v], distY[v]) - cost1[v];
    }

    for (int i = 0; i < m; i++)
        findSubtree(path[i], -1, path[i]);

    // for (int v = 0; v < n; v++)
    //     printf("%d %lld %lld\n", v, distX[v], distY[v]);
    // for (int v = 0; v < n; v++)
    //     printf("%d %lld %lld\n", v, cost1[v], upgrade[v]);

    int maxScore = 0;
    for (int takeAll = 0; takeAll < 2; takeAll++) {
        for (int v = 0; v < n; v++)
            level[v] = 0;

        long long c = 0;
        int score = 0;
        priority_queue<aaa> pq1, pq2;
        for (int v = 0; v < n; v++) {
            if (onPath[v] && takeAll) {
                c += cost1[v];
                level[v] = 1;
                pq1.push({1, v, upgrade[v]});
                score++;
            } else {
                if (takeAll) {
                    if (upgrade[v] >= cost1[v])
                        pq1.push({0, v, cost1[v]});
                    else
                        pq2.push({0, v, cost1[v] + upgrade[v]});
                } else
                    pq1.push({0, v, cost1[v]});
            }
        }

        if (c > k)
            continue;

        bool done = false;
        while (!pq1.empty() && !pq2.empty() && !done) {
            auto p1 = pq1.top();
            pq1.pop();

            auto p2 = pq2.top();
            pq2.pop();

            if (level[p1.v] > p1.t) {
                pq2.push(p2);
                continue;
            }

            if (level[p2.v] > p2.t) {
                pq1.push(p1);
                continue;
            }


            long long c11 = INF;
            while (!pq1.empty() && level[pq1.top().v] != pq1.top().t)
                pq1.pop();
            if (!pq1.empty()) 
                c11 = p1.c + pq1.top().c;
            long long c22 = p2.c;

            // printf("COMPAR %lld %lld\n", c11, c22);

            done = true;
            if (c11 < c22) {
                // auto p11 = pq1.top();
                // pq1.pop();

                if (c + c11 <= k) {
                    done = false;
                    // c += c11;
                    c += p1.c;
                    // score += 2;
                    score++;
                    level[p1.v]++;
                    // level[p11.v]++;
                    // printf("DIN PQ1 %d %d\n", p1.v, p11.v);
                    if (takeAll) {
                        if (p1.t == 0)
                            pq1.push({1, p1.v, upgrade[p1.v]});
                        // if (p11.t == 0)
                        //     pq1.push({1, p11.v, upgrade[p11.v]});
                    }

                } else {
                    pq1.push(p1);
                    // pq1.push(p11);
                }

                pq2.push(p2);
            } else { 
                if (c + c22 <= k) {
                    // printf("DIN PQ2 %d\n", p1.v);
                    done = false;
                    c += c22;
                    score += 2;
                    level[p2.v] = 2;
                } else
                    pq2.push(p2);

                pq1.push(p1);
            }
            // printf("%lld\n", c);
        }

        while (!pq1.empty()) {
            auto p1 = pq1.top();
            pq1.pop();

            if (level[p1.v] > p1.t) 
                continue;

            if (c + p1.c <= k) {
                c += p1.c;
                score++;
                level[p1.v]++;
                if (takeAll && p1.t == 0)
                    pq1.push({1, p1.v, upgrade[p1.v]});
            }
            // printf("%lld\n", c);
        }

        while (!pq2.empty()) {
            auto p2 = pq2.top();
            pq2.pop();

            if (level[p2.v] > 0)
                continue;

            if (c + p2.c <= k) {
                c += p2.c;
                score += 2;
                level[p2.v] = 2;
            }
            // printf("%lld\n", c);
        }

        // printf("%d %d\n", takeAll, score);
        maxScore = max(maxScore, score);
    }


    for (int v = 0; v < n; v++) {
        adj[v].clear();
        subtree[v].clear();
        parent[v] = 0;
        distX[v] = distY[v] = 0;
        onPath[v] = false;
        path.clear();
    }

    return maxScore;
}

#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...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...