zoukankan      html  css  js  c++  java
  • [NOI2015]软件包管理器(树链剖分)

    题目链接

    树链剖分入门好题!

    我们将 $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) << "
    ";
                cc(0, x, 1);
            } else {
                cout << ask(1, pos[x], lst[x]) << "
    ";
                change(1, pos[x], lst[x], 0);
            }
        }
        return 0;
    }
  • 相关阅读:
    在 ASP.NET 2.0 中上载文件
    ASP.NET(C#)FileUpload实现上传限定类型和大小的文件到服务器<from Copying>
    aspnetupload 上传组件在VS2008中使用详细说明
    基于asp.net 的文件上传和下载~~~转
    设置竖直的分割符【使用div】 (根据屏幕的大小自适应)
    分隔线
    UGUI事件系统
    U3D音频系统
    Unity启动事件-监听:InitializeOnLoad
    VS生成桌面应用程序
  • 原文地址:https://www.cnblogs.com/zcr-blog/p/12620035.html
Copyright © 2011-2022 走看看