Submission #1317239

#TimeUsernameProblemLanguageResultExecution timeMemory
1317239h1drogenFactories (JOI14_factories)C++20
100 / 100
2183 ms269828 KiB
#include "factories.h"
#include <bits/stdc++.h>
using namespace std;

const long long INF = 1e18;
const int LOGN = 20; // максимум глубины центроидного дерева
int N;
vector<vector<pair<int,int>>> g;
vector<int> sz, par, us;
vector<long long> dp, best;
vector<int> tin, tout;
int up[LOGN+1][500500];
int tim;

// Предвычисленные расстояния до центроид-предков
vector<vector<long long>> dist_pre;

// ================= DFS и LCA =================
void dfs(int v,int p,long long sum){
    tin[v]=tim++;
    dp[v]=sum;
    up[0][v]=p;
    for(int i=1;i<=LOGN;i++)
        up[i][v]=up[i-1][up[i-1][v]];
    for(auto [to,c]:g[v]){
        if(to!=p)
            dfs(to,v,sum+c);
    }
    tout[v]=tim;
}

bool check(int a,int b){
    return tin[a]<=tin[b] && tout[b]<=tout[a];
}

int lca(int a,int b){
    if(check(a,b)) return a;
    if(check(b,a)) return b;
    for(int i=LOGN;i>=0;i--){
        if(!check(up[i][a],b))
            a = up[i][a];
    }
    return up[0][a];
}

long long dist(int a,int b){
    return dp[a]+dp[b]-2*dp[lca(a,b)];
}

// ================= Центроидное разложение =================
void precalc(int v,int p){
    sz[v]=1;
    for(auto [to,_]:g[v]){
        if(to!=p && !us[to]){
            precalc(to,v);
            sz[v]+=sz[to];
        }
    }
}

int get(int v,int p,int n){
    for(auto [to,_]:g[v]){
        if(sz[to]>n/2 && to!=p && !us[to])
            return get(to,v,n);
    }
    return v;
}

void build(int v,int p){
    precalc(v,-1);
    int c = get(v,-1,sz[v]);
    us[c] = 1;
    par[c] = p;
    for(auto k:g[c]){
        if(!us[k.first])
            build(k.first,c);
    }
}

// ================= Предвычисление dist до центроид-предков =================
void prep_dist(int v){
    int cur = v;
    while(cur >= 0){
        dist_pre[v].push_back(dist(v,cur));
        cur = par[cur];
    }
}

// ================= Обновления и запросы =================
void upd(int v){
    int cur = v;
    int lvl = 0;
    while(cur >= 0){
        best[cur] = min(best[cur], dist_pre[v][lvl]);
        cur = par[cur];
        lvl++;
    }
}

void res(int v, long long &ans){
    int cur = v;
    int lvl = 0;
    while(cur >= 0){
        ans = min(ans, dist_pre[v][lvl] + best[cur]);
        cur = par[cur];
        lvl++;
    }
}

void nulify(int v){
    int cur = v;
    while(cur >= 0){
        best[cur] = INF;
        cur = par[cur];
    }
}

// ================= Батч API =================
void Init(int _N, int A[], int B[], int D[]) {
    N = _N;
    tim = 0;
    g.assign(N, {});
    dp.assign(N,0);
    tin.assign(N,0);
    tout.assign(N,0);
    sz.assign(N,0);
    best.assign(N, INF);
    us.assign(N,0);
    par.assign(N,-1);
    dist_pre.assign(N, {});

    for(int i=0;i<N-1;i++){
        g[A[i]].push_back({B[i], D[i]});
        g[B[i]].push_back({A[i], D[i]});
    }

    dfs(0,0,0);
    build(0,-1);

    for(int i=0;i<N;i++)
        prep_dist(i); // предвычисляем dist до центроид-предков
}

long long Query(int S, int X[], int T, int Y[]) {
    for(int i=0;i<S;i++)
        upd(X[i]);

    long long ans = INF;
    for(int i=0;i<T;i++)
        res(Y[i], ans);

    for(int i=0;i<S;i++)
        nulify(X[i]);

    return ans;
}
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...
#Verdict Execution timeMemoryGrader output
Fetching results...