【NOI 2015 软件包管理器】【树剖】

来源:互联网 发布:矩阵的乘法计算方法 编辑:程序博客网 时间:2024/06/08 15:27

Luogu P2146 软件包管理器

思想有点妙 …

  • 每次安装软件,就把根节点到 x 软件路径上的值全部变为 1
  • 同理,每次卸载软件,就把 x 以及它的子树的值变为 0

故我们可以用区间和的思想,每次操作之前记录一下 tr[root].sum 的值,更新之后再查询一遍 tr[root].sum 的值,两者之差的绝对值则为答案。

然后注意一下细节,比如 lazy 更新完以后要么是 0 要么是 1,所以判断的时候和普通不一样;还有因为实际根节点是从 0 开始的,线段树我的根节点是从 1 开始的,所以要注意每次调用要想清楚到底调用的是实际的还是线段树的。

#include <bits/stdc++.h>#define ll long longusing namespace std;const int N = 1e5 + 5;int n;int a[N], head[N];struct Edge {    int to, next;}e[N << 1];int cnt = 0;void add(int u, int v) {    e[++ cnt].to = v;    e[cnt].next = head[u];    head[u] = cnt;}//---------int fa[N], dep[N], son[N], size[N];void dfs1(int u, int f, int depth) {    fa[u] = f;    dep[u] = depth;    size[u] = 1;    for (int i = head[u]; i; i = e[i].next) {        int v = e[i].to;        if (v != f) {            dfs1(v, u, depth + 1);            size[u] += size[v];            if (son[u] == -1 || size[son[u]] < size[v])                son[u] = v;        }    }}   int tim = 0;int top[N], tid[N], Rank[N];void dfs2(int u, int tp) {    top[u] = tp;    tid[u] = ++ tim;    Rank[tim] = u;    if (son[u] == -1) return ;    dfs2(son[u], tp);    for (int i = head[u]; i; i = e[i].next) {        int v = e[i].to;        if (v != fa[u] && v != son[u])            dfs2(v, v);     }}//----------struct Node {    int sum, lazy;  }tr[N << 2];void pushup(int i) { tr[i].sum = tr[i << 1].sum + tr[i << 1 | 1].sum; }void pushdown(int i, int l, int r) {    if (tr[i].lazy != -1) {        tr[i << 1].lazy = tr[i].lazy;        tr[i << 1 | 1].lazy = tr[i].lazy;        ll mid = (l + r) >> 1;        tr[i << 1].sum = tr[i].lazy * (mid - l + 1);        tr[i << 1 | 1].sum = tr[i].lazy * (r - mid);        tr[i].lazy = -1;     }}void build(int i, int l, int r) {    tr[i].lazy = -1;    if (l == r) tr[i].sum = 0;    else {        ll mid = (l + r) >> 1;        build(i << 1, l, mid);        build(i << 1 | 1, mid + 1, r);        pushup(i);    }}void update(int i, int l, int r, int ql, int qr, int x) {    if (ql > r || qr < l) return ;    if (ql <= l && r <= qr)  {        tr[i].sum = (r - l + 1) * x;        tr[i].lazy = x;     } else {        pushdown(i, l, r);        ll mid = (l + r) >> 1;        update(i << 1, l, mid, ql, qr, x);        update(i << 1 | 1, mid + 1, r, ql, qr, x);        pushup(i);    }}//----------void query(int u, int v, int x) {    while (top[u] != top[v]) {        if (dep[top[u]] < dep[top[v]]) swap(u, v);        update(1, 1, n, tid[top[u]], tid[u], x);        u = fa[top[u]];    }    if (dep[u] > dep[v]) swap(u, v);    update(1, 1, n, tid[u], tid[v], x);}int main() {    memset(son, -1, sizeof(son));    int a;    scanf("%d", &n);    for (int i = 1; i < n; i ++)        scanf("%d", &a), add(a, i);    dfs1(0, 0, 1), dfs2(0, 0);    build(1, 1, n);    int q;    scanf("%d", &q);    while (q --) {        char c[10]; int x;        cin >> c; scanf("%d", &x);        int t1 = tr[1].sum;        if (c[0] == 'i') {            query(0, x, 1);            int t2 = tr[1].sum;            printf("%d\n", abs(t2 - t1));        } else if (c[0] == 'u') {            update(1, 1, n, tid[x], tid[x] + size[x] - 1, 0);            int t2 = tr[1].sum;            printf("%d\n", abs(t2 - t1));        }    }    return 0;   }