[洛谷 2146] [NOI2015]软件包管理器 --- 树链剖分

传送

分析

本题几乎为裸的树剖,假设初始化所有点权均为1。
对于install而言,是对树链进行操作,直接求相应区间的权值和即可,顺便将区间的点权修改为0;
对于uninstall而言,是对子树进行操作,则ans = size(子树) - sum(子树)即可,顺便将子树的点权修改为1;

代码

#include <cstdio>
#include <cstdlib>
#include <cstring>

#define IL inline

using namespace std;

IL int read()
{
    char c=getchar();
    int sum=0,k=1;
    for(;'0'>c || c>'9';c=getchar())
        if(c=='-') k=-1;
    for(;'0'<=c && c<='9';c=getchar()) sum=sum*10+c-'0';
    return sum*k;
}

const int maxn = 1e5 + 5;

int to[maxn];
int nxt[maxn];
int last[maxn];
int cnt;
IL void add(int u, int v)
{
    to[++cnt] = v; nxt[cnt] = last[u]; last[u] = cnt;
}

int lazy[maxn * 3];
int sum[maxn * 3];
int lch[maxn * 3];
int rch[maxn * 3];

IL void pushdown(int p, int len)
{
    int k;
    if(lch[p])
    {
        k = lch[p];
        lazy[k] = lazy[p];
        sum[k] = lazy[p] * (len + 1 >> 1);
    }
    if(rch[p])
    {
        k = rch[p];
        lazy[k] = lazy[p];
        sum[k] = lazy[p] * (len >> 1);
    }
    lazy[p] = -1;
}

IL void build(int &k, int l, int r)
{
    int p = k;
    lazy[p] = -1;
    if(l == r) { sum[p] = 1;  return ; }
    int mid = (l + r) >> 1;
    lch[p] = ++k; build(k, l, mid);
    rch[p] = ++k; build(k, mid + 1, r);
    sum[p] = sum[lch[p]] + sum[rch[p]];
}

IL int update(int p, int l, int r, int x, int y, int w)
{
    if(l == x && r == y)
    {
        int s = sum[p];
        lazy[p] = w;
        sum[p] = w * (r - l + 1);
        return s;
    }
    if(lazy[p] != -1) pushdown(p, r - l + 1);
    int mid = (l + r) >> 1;
    int ans = 0;
    if(y <= mid) ans = update(lch[p], l, mid, x, y, w); else
    if(mid < x) ans = update(rch[p], mid + 1, r, x, y, w); else
    ans = update(lch[p], l, mid, x, mid, w) + update(rch[p], mid + 1, r, mid + 1, y, w);
    sum[p] = sum[lch[p]] + sum[rch[p]];
    return ans;
}

int n;
int fa[maxn];
int dep[maxn];
int size[maxn];
int son[maxn];
int top[maxn];
int id[maxn];

IL void dfs1(int u, int f)
{
    fa[u] = f;
    dep[u] = dep[f] + 1;
    size[u] = 1;

    for(int i = last[u], v; i; i = nxt[i])
    {
        v = to[i];
        dfs1(v, u);
        size[u] += size[v];
        if(size[son[u]] < size[v]) son[u] = v; 
    }
}

IL void dfs2(int u, int topf)
{
    id[u] = ++cnt;
    top[u] = topf;

    if(!son[u]) return ; dfs2(son[u], topf);
    for(int i = last[u], v; i; i = nxt[i])
    if(to[i] != son[u])
        dfs2(to[i], to[i]);
}

IL int swap_(int &x, int &y) { int tmp = x; x = y; y = tmp; }

IL int query(int x, int y)
{
    int ans = 0;
    for(; top[x] != top[y];)
    {
        if(dep[top[x]] < dep[top[y]]) swap_(x, y);
        ans += update(1, 1, n, id[top[x]], id[x], 0);
        x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap_(x, y);
    ans += update(1, 1, n, id[x], id[y], 0);
    return ans;
} 

int main()
{
    n = read();
    for(int i = 2; i <= n; ++i) add(read() + 1, i);

    dfs1(1, 0);
    cnt = 0; dfs2(1, 1);
    int k = 1; build(k, 1, n);

    char c;
    for(int t = read(), x; t; --t)
    {
        scanf(" %c", &c);
        x = read() + 1;
        if(c == 'i') printf("%d\n", query(1, x)); else
        if(c == 'u') printf("%d\n", size[x] - update(1, 1, n, id[x], id[x] + size[x] - 1, 1));
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_27121257/article/details/79519646