Submission #1245362

#TimeUsernameProblemLanguageResultExecution timeMemory
1245362ProtonDecay314Sprinkler (JOI22_sprinkler)C++20
100 / 100
882 ms94372 KiB
/*
stuff i need to do:
- might need to make a permutation inverter
- compute preorder, make a translation table from tree index to preorder index
- compute subtree sizes; make sure to index by preorder
- compute BFS order, make a translation table from tree index to BFS index (and vice versa)
- segtree over BFS order

subroutine: binary search for the first node that's a subtree of some other node and is at some given depth
observation: dfs index is monotonic over a single level of a tree
first node invariant: l = set of all nodes such that dep[i] < dep_targ or dep[i] == dep_targ and dfs_order[i] < dfs_order[targ]
r is the first node

last node invariant: r = set of all nodes such that dep[i] > dep_targ or dep[i] == dep_targ and not within tree and sz[dfs_order[targ]] < dfs_order[i] - dfs_order[targ] + 1ll
*/
#pragma GCC optimize("O3", "unroll-loops")
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef vector<ll> vll;
typedef vector<vll> vvll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<vvi> v3i;
typedef vector<v3i> v4i;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef pair<int, int> pi;
typedef pair<ll, ll> pll;
typedef vector<pi> vpi;
typedef vector<pll> vpll;
#define INF(dt) numeric_limits<dt>::max()
#define NINF(dt) numeric_limits<dt>::min()
#define pb push_back

ll MOD = 1ll; // TODO set this to the correct value later on!

void printv(const vll& a) {
    for(ll v : a) cerr << v << " ";
    cerr << endl;
}

/*
input: a target node (in original indexing) and a target depth
output: two node indices (in BFS order) 

first node invariant: l = set of all nodes such that dep[i] < dep_targ or dep[i] == dep_targ and dfs_order[i] < dfs_order[targ]
r is the first node

last node invariant: r = set of all nodes such that dep[i] > dep_targ or dep[i] == dep_targ and not within tree and sz[dfs_order[targ]] < dfs_order[i] - dfs_order[targ] + 1ll
l is the last node
*/

void find_par(ll i, ll pr, vll& par, const vvll& adj) {
    par[i] = pr;
    
    for(ll j : adj[i]) {
        if(j == pr) continue;

        find_par(j, i, par, adj);
    }
}

int main() {
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    
    // inputting graph information
    ll n;
    cin >> n >> MOD;

    vvll adj(n, vll());

    for(ll i = 0ll; i < n - 1ll; i++) {
        ll a, b;
        cin >> a >> b;

        a--; b--;

        adj[a].pb(b);
        adj[b].pb(a);
    }

    // find parents

    vll par(n, -1ll);

    find_par(0ll, 0ll, par, adj);

    // store updates
    const ll MAXD = 40ll;
    vvll upds(n, vll(MAXD + 1ll, 1ll));

    vll init(n, 0ll);
    for(ll i = 0ll; i < n; i++) cin >> init[i]; 

    // perform the updates
    ll q;
    cin >> q;

    while(q--) {
        int qt;
        cin >> qt;

        if(qt == 1) {
            // upd
            ll x, d, w;
            cin >> x >> d >> w;

            x--;
            ll cur_d = d;
            ll cur_n = x;

            while(cur_d >= 0ll) {
                if(par[cur_n] != cur_n) {
                    // "normal" update

                    upds[cur_n][cur_d] *= w;
                    upds[cur_n][cur_d] %= MOD;

                    if(cur_d > 0ll) {
                        upds[cur_n][cur_d - 1ll] *= w;
                        upds[cur_n][cur_d - 1ll] %= MOD;
                    }
                    cur_d--;
                } else {
                    // update to completion

                    for(ll i = 0ll; i <= cur_d; i++) {
                        upds[cur_n][i] *= w;
                        upds[cur_n][i] %= MOD;
                    }

                    break;
                }

                cur_n = par[cur_n];
            }
        } else {
            // qry
            ll x;
            cin >> x;
            x--;
            ll res = init[x];

            ll cur_n = x;
            ll cur_d = 0ll;

            while(cur_d <= MAXD) {
                res = (res * upds[cur_n][cur_d]) % MOD;

                cur_d++;

                if(par[cur_n] == cur_n) break;
                cur_n = par[cur_n];
            }

            cout << res << "\n";
        }
    }

    cout << flush;

    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...