제출 #872813

#제출 시각아이디문제언어결과실행 시간메모리
872813bobbilykingDynamic Diameter (CEOI19_diameter)C++17
49 / 100
5010 ms41924 KiB
// annoying impl i dont want to deal with rn

#pragma GCC target ("avx2")
#pragma GCC optimize ("O3")
#pragma GCC optimize ("unroll-loops")

#include<bits/stdc++.h>
#include<math.h>
using namespace std;

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

#define K first
#define V second
#define G(x) ll x; cin >> x;
#define GD(x) ld x; cin >> x;
#define GS(s) string s; cin >> s;
#define EX(x) { cout << x << '\n'; exit(0); }
#define A(a) (a).begin(), (a).end()
#define F(i, l, r) for (ll i = (l); i < r; ++i)

#define NN 100010
#define M 1000000007 // 998244353

vector<pl> adj[NN];

ll belong[NN], w[NN]; // maps original edge -> which edge it belongs to now

ll down[NN], par[NN]; // in the new tree, the node below edge I = down[i], and parent of node X in new tree
ll parEdge[NN]; // wehn traversing par, what is the edge I use
ll curw[NN]; // current weight of edge 

ll edgeidx = 0; 

void dfs(ll i, ll p, ll vpar) {
    ll children = 0;
    for (auto [x, _]: adj[i]) if (x-p) children++;
    if (children == 1) {
        for (auto [x, eidx]: adj[i]) if (x-p) {
            belong[eidx] = edgeidx;
            dfs(x, i, vpar);
        }
    } else {
        if (i != p) {
            down[edgeidx] = i;
            par[i] = vpar;
            parEdge[i] = edgeidx;
            edgeidx++;
        }
        for (auto [x, eidx]: adj[i]) if (x-p) {
            belong[eidx] = edgeidx;
            dfs(x, i, i);
        }
    }
}

multiset<ll> all_answer; // all subtree answers
ll curans[NN]; //current answer

multiset<ll> childrenPull[NN]; // the curD's of my children

map<ll, ll> children[NN]; // children -> curD

ll ROOT(ll i) {
    return par[i] == i || par[i] == -1;
}
void multiset_erase(multiset<ll>& a, ll value){
    assert(a.find(value) != a.end());
    a.erase(a.find(value));
}

ll getOneEdge(ll i) { // CANNOT be 1
    assert(childrenPull[i].size() != 1); 
    if (childrenPull[i].size() == 0) return 0;
    return *childrenPull[i].rbegin();
}

void recompute(ll i, ll modified) {
    // cout << "asking to recompute " << i << " with child " << modified << " modified " << endl; 
    // cout << "lol " << i << " " << modified << endl;
    // recomptues maximal down

    // cout << "LOL " << childrenPull[i].size() << ": ";
    // for (auto x: childrenPull[i]) cout << x << " , "; cout << endl;

    assert(children[i].count(modified));
    multiset_erase(childrenPull[i], children[i][modified]);
    children[i][modified] = curw[parEdge[modified]] + getOneEdge(modified);
    childrenPull[i].insert(children[i][modified]);

    // cout << "OK: recomputed. My things are:  \n";
    // for (const auto [k, v]: children[i]) cout << k << ": " << v << endl;
    // cout << "children pull: ";
    // for (const auto x: childrenPull[i]) cout << x << " "; cout << endl;
    
    // cout << parEdge[modified] << ":WTF " << curw[parEdge[modified]] << endl;

    assert(children[i].size() == childrenPull[i].size());

    // cout << "Yo " << endl;
    // recomputes answer
    multiset_erase(all_answer, curans[i]);

    if (childrenPull[i].size() <= 1) 
        curans[i] = getOneEdge(i);
    else {
        // cout << "wtf " << endl;
        auto v = childrenPull[i].rbegin();
        ll t = *v;
        
        v = ++childrenPull[i].rbegin();
        t += *v;

        // cout << "AFTER " << t << endl;
        curans[i] = t;
    }
    // cout << "Ya " << endl;

    all_answer.insert(curans[i]);
    if (!ROOT(i)) recompute(par[i], i);
}

int main(){
//    freopen("a.in", "r", stdin);
//    freopen("a.out", "w", stdout);

    ios_base::sync_with_stdio(false); cin.tie(0);
    cout << fixed << setprecision(20);
    G(n) G(q) G(W)
    memset(par, -1, sizeof par);
    vector<ll> weights(n-1);
    vector<pl> shits;
    F(i, 0, n-1) {
        G(x) G(y) cin >> weights[i];
        adj[x].emplace_back(y, i);
        adj[y].emplace_back(x, i);
        shits.emplace_back(x, y);
    }


    // We want to dfs from a non-leaf root node.
    // Unless n=2; then it's trivial.

    if (n==2) {
        ll last = 0;
        while (q--) {
            G(d) G(e)
            d = (d + last)%(n-1);
            e = (e + last)%W;
            last = e;
            cout << last << '\n';
        }
        exit(0);    
    }

    F(root, 1, n+1) if (adj[root].size() >1) {
        dfs(root, -1, root); break;
    }

    F(i, 1, n+1) if (~par[i]) {
        if (!ROOT(i)) {
            children[par[i]][i] = 0;
            childrenPull[par[i]].insert(0);
        }
        all_answer.insert(curans[i] = 0);

        // cout << "Alive: " << i << endl;
    }
    // F(i, 0, n-1) cout << i << " -> " << belong[i] << endl;

    auto upd = [&](ll i, ll we) {
        ll cur = belong[i];
        curw[cur] -= w[i];
        w[i] = we;
        curw[cur] += w[i];

        // cout << "just updated, thought new cur " << cur << " is " << curw[cur] << endl;

        // cout << "wee wee " << i << " " << we << endl;
        // cout << "THIS BELONGS TO " << belong[i] << endl;
        // cout << "BELONG I SPANS " << down[cur] << "TO " << par[down[cur]] << endl;
        assert(par[down[cur]] != down[cur]);
        recompute(par[down[cur]], down[cur]);
    };

    F(i, 0, n-1) upd(i, weights[i]);

    ll last = 0;
    
    // cout << "current: " << endl;
    // F(k, 1, n+1) cout << k << ": " << curans[k] << endl;


    while (q--) {
        G(d) G(e)
        d = (d + last)%(n-1);
        e = (e + last)%W;
        // cout << "Modifying " << d << " to " << e << endl;

        // if (q == 0){
        //     F(i, 0, n-1) {
        //         cout << shits[i].K << " " << shits[i].V << " " << w[i] << endl;
        //     }
        //     F(j, 0, edgeidx) {
        //         cout << "FAKE EDGE " << j << " FROM " << down[j] << " to " << par[down[j]] << ": " << curw[j] << endl;
        //     }
        // }

        upd(d, e);
        // cout << "current: " << endl;
        // F(k, 1, n+1) cout << k << ": " << curans[k] << endl;

        last = *all_answer.rbegin();
        cout << last << '\n';
    }
}
#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...