2021牛客暑期多校训练营9

2021牛客暑期多校训练营9_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ

E - Eyjafjalla

因为题目保证了每条链上的温度是递减的,所以可以考虑线段树合并的做法。

具体的,我们先将所有询问离线,其中对于每个询问\((x,l,r)\)我们找到最大的满足以下条件的祖先\(y\)

\(\bullet\) \(t_y \leq r\)

这个部分可以倍增完成,然后我们对于每个询问在合并到\(y\)的时候处理即可。

对于刚开始不在区间内的直接特判。

关于线段树合并的部分,对于每个节点\(x\)的线段树,我们先在\(t_x\)的位置设置初值\(1\)代表这棵线段树第\(t_x\)的位置有\(1\)个数,然后不断将每个位置的节点个数向上合并。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e5 + 5;
#define ls(x) tree[x].l
#define rs(x) tree[x].r
struct SegmentTreeNode {
    int l, r, val;
} tree[MAXN * 50]; int idx;
int root[MAXN], L = 1, R = 1e9;
void pushup(int p) {
    tree[p].val = tree[ls(p)].val + tree[rs(p)].val;
}
void insert(int i, int l, int r, int& p) {
    if (!p) p = ++idx;
    if (l == r) {
        ++tree[p].val;
        return ;
    }
    int mid = (l + r) >> 1;
    if (i <= mid) insert(i, l, mid, ls(p));
    else insert(i, mid + 1, r, rs(p));
    pushup(p);
}
int merge(int l, int r, int x, int y) {
    if (!x || !y) return x + y;
    if (l == r) {
        tree[x].val += tree[y].val;
        return x;
    }
    int mid = (l + r) >> 1;
    ls(x) = merge(l, mid, ls(x), ls(y));
    rs(x) = merge(mid + 1, r, rs(x), rs(y));
    pushup(x);
    return x;
}
int query(int ql, int qr, int l, int r, int p) {
    if (!p) return 0;
    if (ql <= l && r <= qr) {
        return tree[p].val;
    }
    int mid = (l + r) >> 1, res = 0;
    if (ql <= mid) res += query(ql, qr, l, mid, ls(p));
    if (qr > mid) res += query(ql, qr, mid + 1, r, rs(p));
    return res;
}
vector<int> e[MAXN];
void addedge(int u, int v) {
    e[u].push_back(v);
    e[v].push_back(u);
}
struct Query {
    int idx, l, r;
};
vector<Query> Q[MAXN];
int w[MAXN], ans[MAXN];
// w存储温度, ans为每个询问的答案
int Log2[MAXN];
void init() {
    for (int i = 1; i < MAXN; ++i) {
        Log2[i] = Log2[i - 1] + (1 << Log2[i - 1] == i);
    }
}
int dp[MAXN][65], depth[MAXN];
void dfs2(int u, int fa) {
    dp[u][0] = fa;
    depth[u] = depth[fa] + 1;
    for (int i = 1; i <= Log2[depth[u]]; ++i) {
        int s = dp[u][i - 1];
        dp[u][i] = dp[s][i - 1];
    }
    for (int v: e[u]) {
        if (v == fa) continue;
        dfs2(v, u);
    }
}
int lca(int x, int r) {
    for (int i = Log2[depth[x]] - 1; i >= 0; --i) {
        if (dp[x][i] && w[dp[x][i]] <= r) {
            x = dp[x][i];
        }
    }
    return x;
}
void dfs(int u, int fa) {
    for (int v: e[u]) {
        if (v == fa) continue;
        dfs(v, u);
        root[u] = merge(L, R, root[u], root[v]);
    }
    for (auto [idx, l, r]: Q[u]) {
        ans[idx] = query(l, r, L, R, root[u]);
    }
}
int main(int argc, char *argv[]) {
    ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
    init();
    int n;
    cin >> n;
    for (int i = 1; i < n; ++i) {
        int u, v;
        cin >> u >> v;
        addedge(u, v);
    }
    for (int i = 1; i <= n; ++i) {
        cin >> w[i];
        insert(w[i], L, R, root[i]);
    }
    dfs2(1, 0);
    int q;
    cin >> q;
    for (int i = 1; i <= q; ++i) {
        int x, l, r;
        cin >> x >> l >> r;
        if (l <= w[x] && w[x] <= r) {
            Q[lca(x, r)].push_back({i, l, r});
        }
        else {
            ans[i] = 0;
        }
    }
    dfs(1, 0);
    for (int i = 1; i <= q; ++i) {
        cout << ans[i] << '\n';
    }
    system("pause");
    return 0;
}
posted @ 2021-08-14 22:23  stler  阅读(92)  评论(0)    收藏  举报