Submission #763630

#TimeUsernameProblemLanguageResultExecution timeMemory
763630CDuongTourism (JOI23_tourism)C++17
100 / 100
3786 ms46060 KiB
/*
#pragma GCC optimize("Ofast,unroll-loops")
#pragma GCC target("avx2,fma,bmi,bmi2,sse4.2,popcnt,lzcnt")
*/

#include <bits/stdc++.h>
#define taskname ""
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define ll long long
#define ld long double
#define pb push_back
#define ff first
#define ss second
#define pii pair<int, int>
#define vi vector<int>
#define vii vector<pii>
using namespace std;

const int mxN = 1e5 + 5;
const int mod = 1e9 + 7;
const int block = 350;
const ll oo = 1e18;

struct query {
    int l, r, idx;
    query() {};
    query(int l, int r, int idx) : l(l), r(r), idx(idx) {}
    bool operator < (const query &o) const {
        int cur_blk = l / block;
        if(cur_blk != o.l / block) return l < o.l;
        return (cur_blk & 1 ? r > o.r : r < o.r);
    }
};

vi G[mxN];
set<int> cur_tree;
pii euler_tour[18][2 * mxN];
int n, m, q, c[mxN], res, ans[mxN], cnt[mxN], cur_tree_sz, fenw[2 * mxN];
int tin[mxN], rev_tin[mxN], tout[mxN], dep[mxN], frst_ap[mxN], euler_cnt, timer;
vector<query> queries;

void dfs(int v, int p) {
    tin[v] = ++timer;
    rev_tin[timer] = v;
    dep[v] = dep[p] + 1;
    frst_ap[v] = ++euler_cnt;
    euler_tour[0][euler_cnt] = {dep[v], v};

    for(int u : G[v]) {
        if(u == p) continue;
        dfs(u, v);
        euler_tour[0][++euler_cnt] = {dep[v], v};
    }

    tout[v] = timer;
}

void build_sparse() {
    for(int i = 1; (1 << i) <= euler_cnt; ++i) {
        for(int j = 1; j + (1 << i) - 1 <= euler_cnt; ++j) {
            euler_tour[i][j] = min(euler_tour[i - 1][j], euler_tour[i - 1][j + (1 << (i - 1))]);
        }
    }
}

int lca(int u, int v) {
    int l = frst_ap[u], r = frst_ap[v];
    if(l > r) swap(l, r);
    int len = r - l + 1;
    int lg_len = 31 - __builtin_clz(len);
    return min(euler_tour[lg_len][l], euler_tour[lg_len][r - (1 << lg_len) + 1]).ss;
}

int dis(int u, int v) {
    int acl = lca(u, v);
    return (dep[u] + dep[v] - 2 * dep[acl]);
}

int ll_nxt[mxN], ll_pre[mxN];

void add_linked_list(int idx, int nxt) {
    int pre = ll_pre[nxt];
    res += dis(pre, idx);
    res += dis(nxt, idx);
    res -= dis(pre, nxt);
    ll_nxt[pre] = ll_pre[nxt] = idx;
    ll_nxt[idx] = nxt, ll_pre[idx] = pre;
}

void del_linked_list(int idx) {
    int pre = ll_pre[idx], nxt = ll_nxt[idx];
    res -= dis(pre, idx);
    res -= dis(nxt, idx);
    res += dis(pre, nxt);
    ll_nxt[pre] = nxt, ll_pre[nxt] = pre;
}

void update(int idx, int val) {
    while(idx <= 2 * n) {
        fenw[idx] += val;
        idx += (idx & (-idx));
    }
}

int get(int idx) {
    int res = 0;
    while(idx) {
        res += fenw[idx];
        idx -= (idx & (-idx));
    }
    return res;
}

int find(int val) {
    int res = 0, mx = 2 * n + 1;
    for(int i = 18; i >= 0; --i) {
        if(res + (1 << i) >= mx) continue;
        if(val > fenw[res + (1 << i)]) {
            val -= fenw[res + (1 << i)];
            res |= (1 << i);
        }
    }
    return res + 1;
}

void add(int idx) {
    ++cnt[c[idx]];
    if(cnt[c[idx]] > 1) return;
    int val = tin[c[idx]];
    if(cur_tree_sz == 0) {
        update(val, 1); ++cur_tree_sz;
        ll_nxt[c[idx]] = ll_pre[c[idx]] = c[idx];
        return;
    }
    int tom = get(val);
    int nxt = find((tom + 1 > cur_tree_sz ? 1 : tom + 1));
    add_linked_list(c[idx], rev_tin[nxt]);
    update(val, 1); ++cur_tree_sz;
}

void del(int idx) {
    --cnt[c[idx]];
    if(cnt[c[idx]]) return;
    int val = tin[c[idx]];
    update(val, -1);
    --cur_tree_sz;
    if(!cur_tree_sz) return;
    del_linked_list(c[idx]);
}

void solve() {
    cin >> n >> m >> q;
    for(int i = 1; i < n; ++i) {
        int u, v; cin >> u >> v;
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }
    dfs(1, 0);
    build_sparse();
    for(int i = 1; i <= m; ++i) {
        cin >> c[i];
    }
    for(int i = 1; i <= q; ++i) {
        int l, r; cin >> l >> r;
        queries.emplace_back(l, r, i);
    }
    sort(all(queries));
    int cur_l = 1, cur_r = 0;
    for(auto &[l, r, idx] : queries) {
        while(cur_l > l) add(--cur_l);
        while(cur_r < r) add(++cur_r);

        while(cur_l < l) del(cur_l++);
        while(cur_r > r) del(cur_r--);

        ans[idx] = (res >> 1) + 1;
    }
    for(int i = 1; i <= q; ++i) {
        cout << ans[i] << "\n";
    }
}

signed main() {

#ifndef CDuongg
    if(fopen(taskname".inp", "r"))
        assert(freopen(taskname".inp", "r", stdin)), assert(freopen(taskname".out", "w", stdout));
#else
    freopen("bai3.inp", "r", stdin);
    freopen("bai3.out", "w", stdout);
    auto start = chrono::high_resolution_clock::now();
#endif

    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    int t = 1; //cin >> t;
    while(t--) solve();

#ifdef CDuongg
    auto end = chrono::high_resolution_clock::now();
    cout << "\n"; for(int i = 1; i <= 100; ++i) cout << '=';
    cout << "\nExecution time: " << chrono::duration_cast<chrono::milliseconds> (end - start).count() << "[ms]" << endl;
#endif

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