NOI2015_软件包管理器

Problem’s Website

  • NOI_2015软件包管理器

    Solution

  • 一道经典的树链剖分题,我们把有依赖关系的软件包用树联系起来,对其进行树剖,设1为已安装,0为未安装,赋值前统计1的个数,赋值后取差值即可。
  • 这道题正解是线段树维护,但本菜鸡为了复习ODT,于是就开O2写了个ODT过了这道题。。。
  • 这道题用ODT维护和线段树差不多,核心就是assign函数,也是ODT复杂度的保证。

    Code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<vector>
    #include<set>
    #define gc getchar()
    #define pc(x) putchar(x)
    #define re register
    const int Maxn = 2e5 + 10;
    inline int sc() {
    int xx = 0, ff = 1; char cch = gc;
    while(!isdigit(cch)) {
    if(cch == '-') ff = -1; cch = gc;
    }
    while(isdigit(cch)) {
    xx = (xx << 1) + (xx << 3) + (cch ^ '0'); cch = gc;
    }
    return xx * ff;
    }
    inline void out(int x) {
    if(x < 0) pc('-'), x = -x;
    if(x >= 10)
    out(x / 10);
    pc(x % 10 + '0');
    }
    inline int aabs(int x) {
    return x > 0 ? x : -x;
    }
    struct ODT {
    int l, r;
    mutable int v;
    bool operator < (const ODT &x) const {
    return l < x.l;
    }
    ODT(int L, int R = -1, int V = 0) : l(L), r(R), v(V) {}
    };
    std :: set <ODT> s;
    #define Int std :: set <ODT> :: iterator
    Int split(int pos) {
    Int it = s.lower_bound(ODT(pos));
    if(it != s.end() && it->l == pos) return it;
    --it;
    int L = it->l, R = it->r, V = it->v;
    s.erase(it), s.insert(ODT(L, pos - 1, V));
    return s.insert(ODT(pos, R, V)).first;
    }
    int assign(int l, int r, int v) {
    Int it2 = split(r + 1), it1 = split(l);
    int sum = 0, SUM = v * (r - l + 1);
    for(Int it = it1; it != it2; ++it)
    sum += it->v * (it->r - it->l + 1);
    s.erase(it1, it2), s.insert(ODT(l, r, v));
    return aabs(SUM - sum);
    }
    struct node {
    int next, to;
    }t[Maxn << 1];
    int n, cnt, m;
    int head[Maxn];
    int dep[Maxn], fa[Maxn], siz[Maxn], id[Maxn], son[Maxn], top[Maxn];
    inline void ADD(int from, int to) {
    t[++cnt].next = head[from];
    t[cnt].to = to;
    head[from] = cnt;
    }
    inline void dfs1(int now, int Fa, int Dep) {
    dep[now] = Dep;
    fa[now] = Fa;
    siz[now] = 1;
    for(re int i = head[now]; i; i = t[i].next) {
    int to = t[i].to;
    if(to == Fa) continue;
    dfs1(to, now, Dep + 1);
    siz[now] += siz[to];
    if(siz[son[now]] < siz[to])
    son[now] = to;
    }
    }
    inline void dfs2(int now, int topf) {
    id[now] = ++cnt;
    // aa[cnt] = a[now];
    top[now] = topf;
    // std :: cerr << cnt << std :: endl;
    if(!son[now]) return;
    dfs2(son[now], topf);
    for(re int i = head[now]; i; i = t[i].next) {
    int to = t[i].to;
    if(to == fa[now] || to == son[now]) continue;
    dfs2(to, to);
    }
    }
    inline int in(int x, int y) {
    int res = 0;
    while(top[x] != top[y]) {
    if(dep[top[x]] < dep[top[y]]) std :: swap(x, y);
    res += assign(id[top[x]], id[x], 1);
    x = fa[top[x]];
    }
    if(dep[x] > dep[y]) std :: swap(x, y);
    res += assign(id[x], id[y], 1);
    return res;
    }
    inline int un(int x) {
    return assign(id[x], id[x] + siz[x] - 1, 0);
    }
    int main() {
    n = sc();
    s.insert(ODT(1, n + 1, 0));
    for(re int i = 2; i <= n; ++i) {
    int x = sc();
    ++x;
    ADD(x, i);
    }
    cnt = 0;
    dfs1(1, 0, 1);
    dfs2(1, 1);
    m = sc();
    while(m--) {
    char c[10];
    std :: cin >> c;
    if(c[0] == 'i') {
    int x = sc();
    ++x;
    out(in(x, 1)), pc('\n');
    }
    else {
    int x = sc();
    ++x;
    out(un(x)), pc('\n');
    }
    }
    return 0;
    }
    // Coded by dy.

rp++