天天看點

樹狀數組樹鍊剖分

其實樹狀數組和線段樹寫樹剖都差不多,隻是換了一種儲存資料的方式,一種占用空間小,但是相對耗時,一種占用空間大,但是很快。

模闆題:​​樹鍊剖分​​

用樹狀數組會 tle 但是這也是一種思路

// Created by CAD on 2019/8/11.
#include <bits/stdc++.h>
using namespace std;
using ll=long long;


#define lowbit(i) (i&-i)
const int maxn=1e5+5;
/*樹狀數組*/
int c[maxn], wt[maxn], laz[maxn << 2];
ll n;
ll mod;

inline void Add(int x, int k)
{
    while (x<=n)
        c[x]=(c[x]+k)%mod, x+=lowbit(x);
}

inline ll getSum(int x)
{
    ll ans=0;
    while (x>0)
        ans=(ans+c[x])%mod, x-=lowbit(x);
    return ans%mod;
}

inline ll getsum(int l, int r, int s, int t, int p)
{
    return (getSum(r)-getSum(l-1)+mod)%mod;
}

int cnt=0, head[maxn << 1];
struct edge {
    int to, next;
} e[maxn << 1];

void add(int u, int v)
{
    e[++cnt].to=v;
    e[cnt].next=head[u];
    head[u]=cnt;
}

int dep[maxn], f[maxn], siz[maxn], son[maxn];
int top[maxn], w[maxn << 1], id[maxn], tot=0;

void dfs1(int x, int fa, int deep)
{
    dep[x]=deep, f[x]=fa, siz[x]=1;
    int maxson=-1;
    for (int i=head[x]; i; i=e[i].next)
    {
        int v=e[i].to;
        if (v==fa) continue;
        dfs1(v, x, deep+1);
        siz[x]+=siz[v];
        if (siz[v]>maxson) maxson=siz[v], son[x]=v;
    }
}

void dfs2(int u, int topf)
{
    id[u]=++tot;
    wt[tot]=w[u];
    top[u]=topf;
    if (!son[u]) return;
    dfs2(son[u], topf);
    for (int i=head[u]; i; i=e[i].next)
    {
        int v=e[i].to;
        if (v==f[u] || v==son[u]) continue;
        dfs2(v, v);
    }
}

ll qrange(int x, int y)
{
    int ans=0;
    while (top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]]) swap(x, y);
        ans=(ans+getsum(id[top[x]], id[x], 1, n, 1)%mod)%mod;
        x=f[top[x]];
    }
    if (dep[x]>dep[y]) swap(x, y);
    ans=(ans+getsum(id[x], id[y], 1, n, 1)%mod)%mod;
    return ans;
}

void updrange(int x, int y, int k)
{
    k%=mod;
    while (top[x]!=top[y])
    {
        if (dep[top[x]]<dep[top[y]])swap(x, y);
        for (register int i=id[top[x]]; i<=id[x]; ++i) Add(i, k);
        x=f[top[x]];
    }
    if (dep[x]>dep[y])swap(x, y);
    for (int i=id[x]; i<=id[y]; ++i) Add(i, k);
}

ll qson(int x)
{
    return getsum(id[x], id[x]+siz[x]-1, 1, n, 1)%mod;
}

void updson(int x, int k)
{
    for (register int i=id[x]; i<=id[x]+siz[x]-1; ++i) Add(i, k);
}

ll m, r;
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cin >> n >> m >> r >> mod;
    for (int i=1; i<=n; ++i) cin >> w[i];
    for (int i=1, u, v; i<n; ++i) cin >> u >> v, add(u, v), add(v, u);
    dfs1(r, 0, 1);
    dfs2(r, r);
    for (int i=1; i<=n; ++i)
        Add(i, wt[i]);
    while (m--)
    {
        int k, x, y, z;
        cin >> k;
        if (k==1)
            cin >> x >> y >> z, updrange(x, y, z);
        else if (k==2)
            cin >> x >> y, cout << qrange(x, y) << endl;
        else if (k==3)
            cin >> x >> y, updson(x, y);
        else if (k==4)
            cin >> x, cout << qson(x) << endl;
    }
    return 0;
}