제출 #1109675

#제출 시각아이디문제언어결과실행 시간메모리
1109675_callmelucianDesignated Cities (JOI19_designated_cities)C++14
39 / 100
2070 ms65684 KiB
#include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef long double ld;
typedef pair<ll,ll> pl;
typedef pair<int,int> pii;
typedef tuple<int,int,int> tpl;

#define all(a) a.begin(), a.end()
#define filter(a) a.erase(unique(all(a)), a.end())

const int mn = 2e5 + 5;

struct IT {
    vector<pl> tr;
    vector<ll> lazy;

    IT (int sz) : tr(4 * sz), lazy(4 * sz) {}

    void apply (int k, ll val) {
        tr[k].first += val, lazy[k] += val;
    }

    void pushDown (int k) {
        if (lazy[k])
            apply(2 * k, lazy[k]), apply(2 * k + 1, lazy[k]), lazy[k] = 0;
    }

    void indexing (int pos, int val, int k, int l, int r) {
        for (; l < r;) {
            int mid = (l + r) >> 1;
            if (pos <= mid) k <<= 1, r = mid;
            else k <<= 1, k |= 1, l = mid + 1;
        }
        tr[k] = make_pair(0, val);
        for (k /= 2; k; k /= 2)
            tr[k] = max(tr[2 * k], tr[2 * k + 1]);
    }

    void update (int a, int b, ll val, int k, int l, int r) {
        if (b < l || r < a) return;
        if (l == r)
            return apply(k, val), void();
        pushDown(k);
        int mid = (l + r) >> 1;
        update(a, b, val, 2 * k, l, mid);
        update(a, b, val, 2 * k + 1, mid + 1, r);
        tr[k] = max(tr[2 * k], tr[2 * k + 1]);
    }

    pl query (int a, int b, int k, int l, int r) {
        if (b < l || r < a) return make_pair(0, 0);
        if (a <= l && r <= b) return tr[k];
        pushDown(k);
        int mid = (l + r) >> 1;
        return max(query(a, b, 2 * k, l, mid), query(a, b, 2 * k + 1, mid + 1, r));
    }
};

vector<tpl> adj[mn];
ll ans[mn], n;

namespace originalTree {
    int bestLeaf[mn], secLeaf[mn];
    ll downPath[mn], upPath[mn], sumDown;

    void dfs (int u, int p, ll pA, ll pH) {
        // construct costs on paths
        downPath[u] = downPath[p] + pA;
        upPath[u] = upPath[p] + pH;
        bestLeaf[u] = u;

        // run dfs down
        for (tpl item : adj[u]) {
            int v, away, home; tie(v, away, home) = item;
            if (v == p) continue;
            dfs(v, u, away, home);

            sumDown += away;
            if (downPath[bestLeaf[v]] > downPath[bestLeaf[u]])
                secLeaf[u] = bestLeaf[u], bestLeaf[u] = bestLeaf[v];
            else if (downPath[bestLeaf[v]] > downPath[secLeaf[u]]) secLeaf[u] = bestLeaf[v];
        }
    }

    ll tryNode (int u) {
        ll pathOne = downPath[bestLeaf[u]] - (bestLeaf[u] ? downPath[u] : 0);
        ll pathTwo = downPath[secLeaf[u]] - (secLeaf[u] ? downPath[u] : 0);
        return sumDown - pathOne - pathTwo - downPath[u] + upPath[u];
    }

    ll chooseNode (int u) {
        return sumDown - downPath[u] + upPath[u];
    }
}

namespace modifiedTree {
    int num[mn], sz[mn], up[mn], timeDfs;
    bool colored[mn];
    ll weight[mn];
    IT tree(mn);

    bool dfs (int u, int p, int y, ll w) {
        num[u] = ++timeDfs, sz[u] = 1, up[u] = p, weight[u] = w;
        if (u == y) colored[u] = 1;
        tree.indexing(num[u], u, 1, 1, n);

        for (tpl item : adj[u]) {
            int v, away, home; tie(v, away, home) = item;
            if (v == p) continue;
            if (dfs(v, u, y, away)) colored[u] = 1;
            sz[u] += sz[v];
        }

        if (!colored[u])
            tree.update(num[u], num[u] + sz[u] - 1, w, 1, 1, n);
        return colored[u];
    }

    pl pickCand() {
        return tree.query(1, n, 1, 1, n);
    }

    void colorNode (int u) {
        while (!colored[u]) {
            tree.update(num[u], num[u] + sz[u] - 1, -weight[u], 1, 1, n);
            colored[u] = 1, u = up[u];
        }
    }
};

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

    cin >> n;
    for (int i = 1; i < n; i++) {
        int a, b, c, d; cin >> a >> b >> c >> d;
        adj[a].emplace_back(b, c, d);
        adj[b].emplace_back(a, d, c);
    }
    originalTree::dfs(1, 1, 0, 0);

    for (int i = 1; i <= n; i++) ans[i] = LLONG_MAX;

    int optX = 0, optY = 0;
    for (int i = 1; i <= n; i++) {
        ll cur = originalTree::tryNode(i);
        if (cur < ans[2])
            ans[2] = cur, optX = originalTree::bestLeaf[i], optY = originalTree::secLeaf[i];

        ans[1] = min(ans[1], originalTree::chooseNode(i));
    }
    modifiedTree::dfs(optX, optX, optY, 0);

    for (int i = 3; i <= n; i++) {
        ll delta; int node; tie(delta, node) = modifiedTree::pickCand();
        ans[i] = ans[i - 1] - delta;
        modifiedTree::colorNode(node);
    }

    int q; cin >> q;
    while (q--) {
        int E; cin >> E;
        cout << ans[E] << "\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...