「Luogu P2146」[NOI2015]软件包管理器

给出一棵以 \(1\) 为根的树,每个结点有一个状态为 \(1\)\(0\) ,初始时为 \(0\) ,给出两种操作,一种询问结点 \(x\) 到根结点路径上状态为 \(0\) 的结点数,并将他们的状态变为 \(0\) ,一种询问结点 \(x\) 的子树内状态为 \(1\) 的结点数,并将他们的状态变为 \(0\)\((1\le n,q\le 100,000)\)

Luogu

LOJ

分析

我们用 \(dep_i\) 来记录 \(i\) 的深度,设 \(k\)\(u\) 到根结点路径上的状态和,那么对于第一种操作的答案即为 \(dep_u-k\) ,用一棵线段树来维护每个结点的状态值和区间状态和,因为询问和修改是同时进行的,我们可以把询问和修改的函数写成一个函数。

对于第一种操作,我们利用树链剖分,每次统计 \(u\)\(top[u]\) 的答案并修改,直到统计完 \(top[u]=1\) 时的答案即可。对于第二种操作,直接利用 \(dfs\) 序计算答案。

注意,输入的结点编号是从 \(0\) 开始的,所以我把所有输入的结点编号都 \(+1\) 了。

代码

#include <bits/stdc++.h>

#define N 100003
#define ls (o<<1)
#define rs (o<<1|1)
#define rg register
#define DEBUG puts("ok")

using namespace std;

inline int gi() {
    rg int x = 0, f = 1; rg char c = getchar();
    for ( ; !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    return x * f;
}

struct Segment { int l, r, sum, tg; } tr[N << 2];

int n, q, tot;
int hd[N], nxt[N];
int dep[N], dfn[N], st[N], ed[N], fa[N], top[N], son[N], sz[N];

inline void insert(int u, int v) { nxt[u] = hd[v], hd[v] = u; }

inline void dfs(int u, int f) {
    dep[u] = dep[f] + 1, fa[u] = f, sz[u] = 1;
    for (rg int v = hd[u]; v; v = nxt[v]) {
        dfs(v, u);
        sz[u] += sz[v];
        if (sz[v] > sz[son[u]]) son[u] = v;
    }
}

inline void dfs2(int u, int tp) {
    top[u] = tp;
    dfn[++tot] = u, st[u] = tot;
    if (son[u]) dfs2(son[u], tp);
    for (rg int v = hd[u]; v; v = nxt[v])
        if (v != son[u]) dfs2(v, v);
    ed[u] = tot;
}

inline void pushup(int o) { tr[o].sum = tr[ls].sum + tr[rs].sum; }

inline void pushdown(int o) {
    if (tr[o].tg != -1) {
        tr[ls].tg = tr[rs].tg = tr[o].tg;
        tr[ls].sum = tr[o].tg * (tr[ls].r - tr[ls].l + 1);
        tr[rs].sum = tr[o].tg * (tr[rs].r - tr[rs].l + 1);
        tr[o].tg = -1;
    }
}

inline void build(int o, int l, int r) {
    tr[o].l = l, tr[o].r = r, tr[o].tg = -1;
    if (l == r) return;
    rg int mid = l + r >> 1;
    build(ls, l, mid), build(rs, mid + 1, r);
}

inline int query(int o, int l, int r, int L, int R, int k) {
    if (l >= L && r <= R) {
        rg int tmp = tr[o].sum;
        tr[o].tg = k, tr[o].sum = (tr[o].r - tr[o].l + 1) * k;
        return tmp;
    }
    pushdown(o);
    rg int mid = l + r >> 1, ret = 0;
    if (L <= mid) ret += query(ls, l, mid, L, R, k);
    if (R > mid) ret += query(rs, mid + 1, r, L, R, k);
    pushup(o);
    return ret;
}

inline int install(int x) {
    rg int tx = 0, ret = 0;
    while (tx != 1) {
        tx = top[x];
        rg int tmp = dep[x] - dep[tx] + 1;
        ret += tmp - query(1, 1, n, st[tx], st[x], 1);
        x = fa[tx];
    }
    return ret;
}

int main() {
    rg int x; rg char op[10];
    n = gi();
    for (rg int i = 2; i <= n; ++i) {
        x = gi() + 1;
        insert(i, x);
    }
    dfs(1, 0);
    dfs2(1, 1);
    build(1, 1, n);
    q = gi();
    for (rg int i = 1; i <= q; ++i) {
        scanf("%s", op);
        x = gi() + 1;
        if (op[0] == 'i') printf("%d\n", install(x));
        else printf("%d\n", query(1, 1, n, st[x], ed[x], 0));
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/hlw1/p/12287345.html