树链剖分

树链剖分

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5 + 9;
template <typename T>
inline void read(T &x) {
    register T f = 0, c = getchar();
    for (; c < 48 || 57 < c; c = getchar())
        if (c == '-') f = 1;
    for (x = 0; 48 <= c && c <= 57; c = getchar())
        x = (x << 3) + (x << 1) + (c & 15);
    if (f) x = ~(--x);
}
template <typename T>
inline void write(T x) {
    if (x < 0) putchar('-'), x = ~(--x);
    if (x > 9) write(x / 10);
    putchar(x % 10 | 48);
}
ll n, m, root, mod;
struct segmentTree {
    struct node {
        int l, r, L, R;
        ll add, sum;
    }tr[N << 2];
    inline void pushup(int p) {tr[p].sum = (tr[tr[p].l].sum*1ll + tr[tr[p].r].sum*1ll)%mod;}
    inline void pushdown(int p) {
        if (tr[p].add) {
            ll d = tr[p].add;
            tr[p].add = 0;
            (tr[tr[p].l].sum += d %mod * (tr[tr[p].l].R - tr[tr[p].l].L + 1)%mod)%=mod;
            (tr[tr[p].r].sum += d %mod * (tr[tr[p].r].R - tr[tr[p].r].L + 1)%mod)%=mod;
            (tr[tr[p].l].add += d)%=mod;
            (tr[tr[p].r].add += d)%=mod;
        }
    }
    inline void build(int l, int r, int p) {
        tr[p].l = p<<1;
        tr[p].r = p<<1|1;
        tr[p].L = l, tr[p].R = r;
        if (l == r) {
            tr[p].sum = 0, tr[p].add = 0;
            return;
        }
        ll mid = l + r >> 1;
        build(l, mid, tr[p].l),build(mid + 1, r, tr[p].r);
        pushup(p);
    }
    inline void add(ll l, ll r, ll p, ll k) {
        if (tr[p].L >= l && tr[p].R <= r) {
            tr[p].add += k;
            tr[p].add %= mod;
            tr[p].sum += (tr[p].R - tr[p].L + 1)%mod * k%mod;
            tr[p].sum %= mod;
            return;
        }
        pushdown(p);
        if (tr[tr[p].l].R >= l)
        add(l, r, tr[p].l, k);
        if (tr[tr[p].r].L <= r)
        add(l, r, tr[p].r,k);
        pushup(p);
    }
    inline int ask(int l, int r, int p) {
        int ret = 0;
        pushdown(p);
        if (tr[p].L >= l && tr[p].R <= r) return tr[p].sum%mod;
        if (tr[tr[p].l].R >= l) (ret += ask(l, r, tr[p].l))%=mod;
        if (tr[tr[p].r].L <= r) (ret += ask(l, r, tr[p].r))%=mod;
        return ret;
    }
}T;
vector<int>G[N];
int size[N], fa[N], dep[N], son[N];
int id[N], top[N], w[N];
int cnt;
void dfs1(int u, int fat) {
    size[u] = 1;
    fa[u] = fat;
    if (fat != -1)
    dep[u] = dep[fat] + 1;
    int t = -1;
    for (auto v:G[u]) {
        if (v == fat)continue;
        dfs1(v, u);
        size[u] += size[v];
        if (size[v] > t) {
            t = size[v];
            son[u] = v;
        }
    }
}
void dfs2(int u, int fat) {
    top[u] = fat;
    id[u] = ++ cnt;
    if (w[u] != 0) {
        T.add(id[u], id[u], 1, w[u]);
    }
    if (son[u] == 0)return;
    dfs2(son[u], fat);
    for (auto v:G[u]) {
        if (v == fa[u] || v == son[u])continue;
        dfs2(v, v);
    }
}
void addPath(int u, int v, int k) {
    k %= mod;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]])
        swap(u, v);
        T.add(id[top[u]], id[u],1, k);
        u = fa[top[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    T.add(id[u], id[v], 1,k);
}
int askPath(int u, int v) {
    ll ret = 0;
    while (top[u] != top[v]) {
        if (dep[top[u]] < dep[top[v]]) swap(u, v);
        ret += T.ask(id[top[u]], id[u], 1);
        ret %= mod;
        u = fa[top[u]];
    }
    if (dep[u] > dep[v]) swap(u, v);
    ret += T.ask(id[u], id[v], 1);
    ret %= mod;return ret;
}
void addSon(int u, int k) {k %= mod;T.add(id[u], id[u] + size[u] - 1,1, k);}
int querySon(int u) { return T.ask(id[u], id[u] + size[u] - 1, 1); }
void solve() {
    read(n), read(m), read(root), read(mod);
    T.build(1, n, 1);
    ll x;
    for (int i = 1; i <= n; i ++) {
        read(w[i]);
        w[i] %= mod;
    }
    for (int i = 1; i < n; i ++) {
        ll u, v;
        read(u), read(v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs1(root, 0);
    dfs2(root, root);
    while (m--) {
        ll op;
        read(op);
        if (op == 1) {
            ll u, v, z;
            read(u), read(v), read(z);
            z %= mod;
            addPath(u, v, z);
            
        }
        if (op == 2) {
            ll u, v;read(u), read(v);
            write(askPath(u, v)%mod);
            puts("");
        }
        if (op == 3) {
            int x, z;read(x), read(z);
            z %= mod;
            addSon(x, z);
        }
        if (op == 4) {
            int x;
            read(x);
            write(querySon(x) %mod);
            puts("");
        }
    }
}
signed main() {
    ll t = 1;//cin >> t;
    while (t--)  solve();
    return 0;
}
posted @ 2021-06-30 19:28  u_yan  阅读(28)  评论(0编辑  收藏  举报