首页 > 其他 > 详细

[NOI2015]软件包管理器(树链剖分)

时间:2020-04-02 16:46:52      阅读:52      评论:0      收藏:0      [点我收藏+]

题目链接

树链剖分入门好题!

我们将 $i$ 所依赖的软件包连向 $i$ 一条边,因为没有环而且仅依赖一个(只有一个父亲)所以这就形成了一棵树。

从根到节点 $x$ 的路径上的点就是建 $x$ 是所需要提前建好的。

节点 $x$ 的子树即为删去 $x$ 所需要提前删的。

这题线段树维护区间内有多少没被删的。

然后对于查询1查询路径 $1->x$ 得到路径上已经安装的软件包的个数 $num$,输出 $x$ 的深度减去 $num$即可。修改将路径 $1->x$ 上的所有数改成1(即安装)。

对于查询2,输出子树中有多少以安装的就行。修改就把子树全部改成0即可。

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 100010;
struct node{
    int pre, to;
}edge[N];
int head[N], tot;
struct seg_tree{
    int val, tag, l, r;
}st[4 * N];
int n, m;
int sz[N];
int depend[N], pos[N], dfn, lst[N], bl[N], dep[N];
int read() {
    int ret = 0, f = 1;
    char ch = getchar();
    while (0 > ch || ch > 9) {
        if (ch == -) {
            f = -1;
        }
        ch = getchar();
    }
    while (0 <= ch && ch <= 9) {
        ret = (ret << 1) + (ret << 3) + ch - 0;
        ch = getchar();
    }
    return ret * f;
}
void add(int u, int v) {
    edge[++tot] = node{head[u], v};
    head[u] = tot;
}
void dfs1(int x) {
    sz[x] = 1;
    for (int i = head[x]; i; i = edge[i].pre) {
        int y = edge[i].to;
        dep[y] = dep[x] + 1;
        dfs1(y);
        sz[x] += sz[y];
    }
}
void dfs2(int x, int chain) {
    pos[x] = lst[x] = ++dfn;
    bl[x] = chain;
    int k = n;
    for (int i = head[x]; i; i = edge[i].pre) {
        int y = edge[i].to;
        if (sz[y] > sz[k]) {
            k = y;
        }
    }
    if (k != n) dfs2(k, chain), lst[x] = max(lst[x], lst[k]);
    for (int i = head[x]; i; i = edge[i].pre) {
        int y = edge[i].to;
        if (y != k) {
            dfs2(y, y);
            lst[x] = max(lst[x], lst[y]);
        }
    }
}
void build(int x, int l, int r) {
    st[x].l = l, st[x].r = r;
    st[x].tag = -1;
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
}
void update(int p) {
    if (st[p].tag != -1) {
        st[p << 1].tag = st[p].tag;
        st[p << 1 | 1].tag = st[p].tag;
        st[p << 1].val = (st[p << 1].r - st[p << 1].l + 1) * st[p].tag;
        st[p << 1 | 1].val = (st[p << 1 | 1].r - st[p << 1 | 1].l + 1) * st[p].tag;
        st[p].tag = -1; 
    }
}
int ask(int p, int x, int y) {
    int l = st[p].l, r = st[p].r;
    if (x > r || y < l) return 0;
    if (x <= l && r <= y) {
        return st[p].val;
    }
    update(p);
    return ask(p << 1, x, y) + ask(p << 1 | 1, x, y);
}
void change(int p, int x, int y, int v) {
    int l = st[p].l, r = st[p].r;
    if (x > r || y < l) return;
    if (x <= l && r <= y) {
        st[p].tag = v;
        st[p].val = (r - l + 1) * v;
        return;
    }
    update(p);
    change(p << 1, x, y, v);
    change(p << 1 | 1, x, y, v);
    st[p].val = st[p << 1].val + st[p << 1 | 1].val;
}
int Q_sum(int u, int v) {
    int ret = 0;
    while (bl[u] != bl[v]) {
        if (dep[bl[u]] < dep[bl[v]]) swap(u, v);
        ret += ask(1, pos[bl[u]], pos[u]);
        u = depend[bl[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    ret += ask(1, pos[u], pos[v]);
    return ret;
}
void cc(int u, int v, int val) {
    while (bl[u] != bl[v]) {
        if (dep[bl[u]] < dep[bl[v]]) swap(u, v);
        change(1, pos[bl[u]], pos[u], val);
        u = depend[bl[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    change(1, pos[u], pos[v], val);
}
int main() {
    cin >> n;
    for (int i = 1; i < n; i++) {
        cin >> depend[i];
        add(depend[i], i);
    }
    dfs1(0);
    dfs2(0, 0);
    build(1, 1, dfn);
    cin >> m;
    while (m--) {
        string opt;
        int x;
        cin >> opt;
        x = read();
        if (opt == "install") {
            cout << dep[x] + 1 - Q_sum(0, x) << "\n";
            cc(0, x, 1);
        } else {
            cout << ask(1, pos[x], lst[x]) << "\n";
            change(1, pos[x], lst[x], 0);
        }
    }
    return 0;
}

 

[NOI2015]软件包管理器(树链剖分)

原文:https://www.cnblogs.com/zcr-blog/p/12620035.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!