求助树链剖分,马蜂还可以

P3384 【模板】重链剖分/树链剖分

jimmy916 @ 2024-08-09 13:31:21

#include <iostream>
#include <cstdio>
#include <vector>
#define ll long long
#define ls(x) (x<<1)
#define rs(x) (x<<1)|1

using namespace std;

const int N = 2 * 1e5 + 1;

struct tree {
    ll l, r;
    ll val;
    ll lazy;
};

ll n, m, root, p;
ll a[N], fa[N], son[N], siz[N], top[N], dfn[N], rnk[N], dep[N];
// a:权值  fa:父亲  son:重子节点  siz:子树大小  top:链顶  dfn:DFS序  rnk:DFS序对应编号  dep:深度 
ll cnt;
vector<ll> g[N];

tree t[N << 2]; // 线段树 

void pushup(ll x) {
    t[x].val = (t[ls(x)].val + t[rs(x)].val);
    return;
}

void pushdown(ll x) {
    if (t[x].l == t[x].r) {
        t[x].lazy = 0;
        return;
    }
    t[ls(x)].val += (t[ls(x)].r - t[ls(x)].l + 1) * t[x].lazy;
    t[rs(x)].val += (t[rs(x)].r - t[rs(x)].l + 1) * t[x].lazy;
    t[ls(x)].lazy += t[x].lazy, t[rs(x)].lazy += t[x].lazy;
    return;
}

void build(ll l, ll r, ll x) {
    t[x].l = l, t[x].r = r;
    if (l == r) {
        t[x].val = a[rnk[l]];
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, ls(x)), build(mid + 1, r, rs(x));
    pushup(x);
    return;
}

void add(ll l, ll r, ll k, ll x) {
    if (t[x].l > r || t[x].r < l)
        return;
    if (l <= t[x].l && t[x].r <= r) {
        t[x].val += (t[x].r - t[x].l + 1) * k;
        t[x].lazy += k;
        return;
    }
    if (t[x].lazy)
        pushdown(x);
    add(l, r, k, ls(x)), add(l, r, k, rs(x));
    pushup(x);
    return;
}

ll ask(ll l, ll r, ll x) {
    if (t[x].l > r || t[x].r < l)
        return 0;
    if (l <= t[x].l && t[x].r <= r)
        return t[x].val;
    if (t[x].lazy)
        pushdown(x);
    ll sum = (ask(l, r, ls(x)) + ask(l, r, rs(x)));
    pushup(x);
    return sum;
}

// 以上是线段树 

void dfs1(ll now, ll fath) { // 求fa, dep, siz, son
    fa[now] = fath, dep[now] = dep[fath] + 1;
    siz[now] = 1;
    for (ll i = 0; i < (ll)g[now].size(); i ++ ) {
        ll v = g[now][i];
        if (v == fath)
            continue;
        dfs1(v, now);
        siz[now] += siz[v];
        if (siz[v] > siz[son[now]])
            son[now] = v;
    }
    return;
}

void dfs2(ll now, ll anc) { // 求top, dfn, rnk
    top[now] = anc;
    dfn[now] = ++ cnt;
    rnk[cnt] = now;
    if (!son[now])
        return;
    dfs2(son[now], anc);
    for (ll i = 0; i < (ll)g[now].size(); i ++ ) {
        ll v = g[now][i];
        if (v != fa[now] && v != son[now])
            dfs2(v, v);
    }
    return;
}

ll ask_range(ll x, ll y) { // 询问链 
    ll sum = 0;
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        sum += ask(dfn[top[x]], dfn[x], 1);
        x = fa[top[x]];
    }
    return sum + ask(min(dfn[x], dfn[y]), dfn[max(dfn[x], dfn[y])], 1);
}

void update_range(ll x, ll y, ll k) { // 更新链 
    while (top[x] != top[y]) {
        if (dep[top[x]] < dep[top[y]])
            swap(x, y);
        add(dfn[top[x]], dfn[x], k, 1);
        x = fa[top[x]];
    }
    add(min(dfn[x], dfn[y]), dfn[max(dfn[x], dfn[y])], k, 1);
    return;
}

ll ask_son(ll x) { // 询问子树 
    return ask(dfn[x], dfn[x] + siz[x] - 1, 1);
}

void update_son(ll x, ll k) { // 更新子树 
    add(dfn[x], dfn[x] + siz[x] - 1, k, 1);
    return;
}

int main() {
    scanf("%lld%lld%lld%lld", &n, &m, &root, &p);
    for (ll i = 1; i <= n; i ++ )
        scanf("%lld", &a[i]);
    for (ll i = 1; i < n; i ++ ) {
        ll x, y;
        scanf("%lld%lld", &x, &y);
        g[x].push_back(y), g[y].push_back(x);
    }
    dfs1(root, 0);
    dfs2(root, root);
    build(1, n, 1);
    while (m -- ) {
        int op;
        cin >> op;
        if (op == 1) {
            ll x, y, k;
            scanf("%lld%lld%lld", &x, &y, &k);
            update_range(x, y, k);
        } else if (op == 2) {
            ll x, y;
            scanf("%lld%lld", &x, &y);
            printf("%lld\n", ask_range(x, y) % p);
        } else if (op == 3) {
            ll x, k;    
            scanf("%lld%lld", &x, &k);
            update_son(x, k);
        } else {
            ll x;
            scanf("%lld", &x);
            printf("%lld\n", ask_son(x) % p);
        }
    }
    return 0;
} 

by UMS2 @ 2024-08-09 14:06:19

@jimmy916 pushdown 内没有清零自己的懒标记。


by jimmy916 @ 2024-08-09 14:08:58

@UMS2 自己发现了,已A,不过还是谢谢


|