Submission #1261785

#TimeUsernameProblemLanguageResultExecution timeMemory
1261785niepamietamhaslaTourism (JOI23_tourism)C++20
0 / 100
1040 ms26404 KiB
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pii pair<int,int>
#define vii vector<pair<int,int>>
#define vi vector<int>

const int MAXN = 1e5 + 5;

struct d{
    int a;
    int b;
    int dist;
};

int n, m, q;
int miejsca[MAXN];

vector<pii> graf[MAXN];
int odlodroota[MAXN];
int gl[MAXN];
int pre[MAXN];
int post[MAXN];
int przodek[MAXN][17];
int wartoscpre[MAXN];

vector<d> szuk;
int cnt = 0;
int it = 0;
set<int> tmp;
vector<int> uzyteczne;

void dfs(int v, int p){
    pre[v] = cnt;
    wartoscpre[cnt] = v;
    //cout << v << " " << pre[v] << " pre\n";
    post[v] = cnt;
    cnt++;
    for(auto u : graf[v]){
        if(u.first == p) continue;
        gl[u.first] = gl[v] + 1;
        przodek[u.first][0] = v;
        odlodroota[u.first] = odlodroota[v] + u.second;
        for(int j = 1; j < 17; ++j){
            przodek[u.first][j] = przodek[przodek[u.first][j-1]][j-1];
        }
        dfs(u.first, v);
        post[v] = post[u.first];
    }
    return;
}

int obliczLCA(int x, int y){
    if(x == y) return x;
    if(gl[x] < gl[y]) swap(x, y);
    for(int i = 16; i >= 0; --i){
        if(gl[x] - (1 << i) >= gl[y]){
            x = przodek[x][i];
        }
    }
    if(x == y) return x;
    for(int i = 16; i >= 0; --i){
        if(gl[x] >= (1 << i) and przodek[x][i] != przodek[y][i]){
            x = przodek[x][i];
            y = przodek[y][i];
        }
    }
    return przodek[x][0];
}

void dfs2(int v, int p){
    bool c = (it != uzyteczne.size() and wartoscpre[uzyteczne[it]] == v);
    if(c) ++it;
    int last = -1;
    for(auto u : graf[v]){
        if(u.first == p) continue;
        if(c and it != last and it != uzyteczne.size() and uzyteczne[it] >= pre[v] and uzyteczne[it] <= post[v]){
            //cout << v << " " << wartoscpre[uzyteczne[it]] << " nowa kraw do grafu\n";
            szuk.push_back({v, wartoscpre[uzyteczne[it]], odlodroota[wartoscpre[uzyteczne[it]]] - odlodroota[v]});
            last = it;
        }
        dfs2(u.first, v);
    }
    return;
}   

void generujkrawedzie(const vector<d> &starekrawedzie, int nowyroot, int poczatekmiejsc, int koniecmiejsc){
    if(poczatekmiejsc >= koniecmiejsc) {
        szuk.clear();
        return;
    }
    cnt = 0;
    it = 0;
    szuk.clear();
    uzyteczne.clear();
    tmp.clear();
    for(auto u : starekrawedzie){
        graf[u.a].push_back({u.b, u.dist});
        graf[u.b].push_back({u.a, u.dist});
    }
    dfs(nowyroot, -1);
    //cout << poczatekmiejsc << " " << koniecmiejsc << " pk\n";
    for(int i = poczatekmiejsc; i <= koniecmiejsc; ++i){
        if(pre[miejsca[i]] != 0) {
            uzyteczne.push_back(pre[miejsca[i]]);
        }
    }
    sort(uzyteczne.begin(),uzyteczne.end());
    for(int i = 0; i < uzyteczne.size()-1; ++i){
        int x = wartoscpre[uzyteczne[i]];
        int y = wartoscpre[uzyteczne[i+1]];
        //cout << x << " " << y << " gen LCA\n";
        int LCA = obliczLCA(x, y);
        //cout << LCA << " LCA\n";
        tmp.insert(pre[LCA]);
    }
    for(auto u : uzyteczne){
        tmp.insert(u);
    }
    tmp.insert(0);
    uzyteczne.clear();
    for(auto u : tmp){
        uzyteczne.push_back(u);
    }
    dfs2(nowyroot, -1);
    for(auto u : starekrawedzie){
        for(auto t : {u.a, u.b}){
            graf[t].clear();
            pre[t] = 0;
            post[t] = 0;
            odlodroota[t] = 0;
            for(int i = 0; i < 17; ++i){
                przodek[t][i] = 0;
            }
            gl[t] = 0;
        }
    }
    for(int i = 0; i < cnt; ++i){
        wartoscpre[i] = 0;
    }
    // for(auto u : szuk){
    //     cout << u.a << " " << u.b << " " << u.dist << " U\n";
    // }
    return;
}

struct e{
    int l;
    int r;
    int org;
};



int ans[MAXN];
pii przedzialy[MAXN];

struct f{
    int l;
    int r;
    int typ;
    int last;
};

vector<f> sweep;

const int base = 1 << 17;
int drzew[base << 1];

void akt(int w, int val){
    w += base;
    while(w != 0){
        drzew[w] += val;
        w /= 2;
    }
    return;
}

int obl(int w, int a, int b, int akt_a, int akt_b){
    if(a <= akt_a and akt_b <= b) return drzew[w];
    if(akt_a > b or akt_b < a) return 0;
    int mid = (akt_a + akt_b) / 2;
    return obl(2 * w, a, b, akt_a, mid) + obl(2 * w + 1, a, b, mid + 1, akt_b);
}

set<int> ind[MAXN];

void dfs3(int v, int p, int mid, int koszt){
    if(ind[v].size() == 0) przedzialy[v] = {0, n + 1};
    else{
        auto it = ind[v].upper_bound(mid);
        if(it == ind[v].begin()) przedzialy[v].first = 0;
        else przedzialy[v].first = *(--it);
        it = ind[v].upper_bound(mid);
        if(it == ind[v].end()) przedzialy[v].second = n+1;
        else przedzialy[v].second = *it;
    }
    for(auto u : graf[v]){
        if(u.first == p) continue;
        dfs3(u.first, v, mid, u.second);
        przedzialy[v].first = max(przedzialy[v].first, przedzialy[u.first].first);
        przedzialy[v].second = min(przedzialy[v].second, przedzialy[u.first].second);
    }
    if(v != miejsca[mid]){
        //cout << v << " " << przedzialy[v].first << " " << przedzialy[v].second << " przedzial\n";
        //cout << przedzialy[v].first << " " << koszt << " ADDDDD\n";
        akt(przedzialy[v].first, koszt);
        sweep.push_back({przedzialy[v].first, przedzialy[v].second, 0, koszt});
    }
    return;
}

bool comp(const f &f1, const f &f2){
    if(f1.r != f2.r) return f1.r < f2.r;
    if(f1.typ != f2.typ) return f1.typ < f2.typ;
    return false;
}

void daq(const vector<d> &kraw, int root, int l, int r, vector<e> &queries){
    if(l > r){
        //cout << l << " " << r << " zly\n";
        return;
    }
    if(l == r){
        //cout << l << " " << r << " rowny\n";
        for(auto u : queries){
            ans[u.org] = 1;
        }
        return;
    }
    // cout << root << " " << l << " " << r << " lr\n";
    // for(auto u : kraw){
    //     cout << u.a << " " << u.b << " " << u.dist << " graf\n";
    // }
    for(int i = l; i <= r; ++i){
        ind[miejsca[i]].insert(i);
    }

    vector<e> lewe;
    vector<e> prawe;
    vector<e> reszta;
    int split = (l + r) / 2;
    for(auto u : queries){
        if(u.r < split) lewe.push_back(u);
        else if(u.l > split) prawe.push_back(u);
        else reszta.push_back(u);
    }

    for(auto u : kraw){
        graf[u.a].push_back({u.b, u.dist});
        graf[u.b].push_back({u.a, u.dist});
    }

    int mid = (l + r) / 2;
    dfs3(root, -1, mid, -1);
    for(auto u : reszta){
        //cout << u.l << " " << u.r << " " << u.org << " zap\n";
        sweep.push_back({u.l, u.r, 1, u.org});
    }
    sort(sweep.begin(),sweep.end(),comp);
    ll S = 0;
    for(auto u : sweep){
        if(u.typ == 0){
            akt(u.l, -u.last);
            S += u.last;
        }
        else{
            ans[u.last] = obl(1, u.l, mid, 0, base - 1) + S + 1;
        }
    }
    sweep.clear();
    for(auto u : kraw){
        graf[u.a].clear();
        graf[u.b].clear();
        przedzialy[u.a] = {0, 0};
        przedzialy[u.b] = {0, 0};
    }
    for(int i = l; i <= r; ++i){
        ind[miejsca[i]].clear();
    }

    // cout << l << " " << mid - 1 << " p1\n";
    // cout << mid + 1 << " " << r << " p2\n";
    if(l <= mid - 1) generujkrawedzie(kraw, miejsca[(l + mid - 1) / 2], l, mid - 1);
    vector<d> G1 = szuk;
    if(mid + 1 <= r) generujkrawedzie(kraw, miejsca[(mid + 1 + r) / 2], mid + 1, r);
    vector<d> G2 = szuk;

    
    if(l <= mid - 1) daq(G1, miejsca[(l + mid - 1) / 2], l, mid - 1, lewe);
    if(mid + 1 <= r) daq(G2, miejsca[(mid + 1 + r) / 2], mid + 1, r, prawe);
    return;
}

int main() {
    // ios::sync_with_stdio(0);
    // cin.tie(0);
    // cout.tie(0);
    cin >> n >> m >> q;
    vector<d> kraw;
    int a, b;
    for(int i = 0; i < n-1; ++i){
        cin >> a >> b;
        kraw.push_back({a, b, 1});
    }
    for(int i = 1; i <= m; ++i){
        cin >> miejsca[i];
    }
    vector<e> zap;
    for(int i = 1; i <= q; ++i){
        cin >> a >> b;
        zap.push_back({a, b, i});
    }
    generujkrawedzie(kraw, miejsca[(m+1)/2], 1, m); 
    auto G = szuk;
    daq(G, miejsca[(m + 1) / 2], 1, m, zap);
    for(int i = 1; i <= q; ++i){
        cout << ans[i] << " ";
    }
    cout << "\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...