学习链接:https://zhuanlan.zhihu.com/p/41082337
其实就是运用了两边dfs维护dfs序之类的信息,然后线段树区间修改,区间查询之类的操作
#include <bits/stdc++.h>
using namespace std;
#define pi acos(-1)
#define xx first
#define yy second
#define endl "\n"
#define lowbit(x) x & (-x)
#define int long long
#define ull unsigned long long
#define pb push_back
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
#define LF(x) fixed << setprecision(x)
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Yshanqian ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
const int N = 1e5 + 10, M = 1010, inf = 0x3f3f3f3f, P = 13331;
const double eps = 1e-8;
int n, m, r, p, cnt, mod;
int a[N];
int son[N], id[N], top[N], siz[N], f[N], rk[N], d[N];
vector<int> g[N];
struct node
{
int l, r, sum;
int lazy;
} tr[N << 2];
void dfs1(int u, int fa, int depth)
{
siz[u] = 1;
f[u] = fa; // 自己的父亲赋为自己
d[u] = depth;
for (auto ed : g[u])
{
if (ed == fa)
continue;
dfs1(ed, u, depth + 1);
siz[u] += siz[ed];
if (siz[ed] > siz[son[u]])
son[u] = ed;
}
}
void dfs2(int u, int t)
{
top[u] = t;
id[u] = ++cnt; // dfs徐的编号
rk[cnt] = u; // dfs序编号对应的原始点编号
if (!son[u]) // 叶子节点
return;
dfs2(son[u], t);
for (auto ed : g[u])
{
if (son[u] != ed && ed != f[u])
dfs2(ed, ed); // 一个点位于轻链底端,那么它的top必然是它本身
}
}
void change(int u, int k)
{
tr[u].sum = ((tr[u].sum + (tr[u].r - tr[u].l + 1) * k % mod) % mod + mod) % mod;
tr[u].lazy += k;
}
void pushdown(int u)
{
if (tr[u].lazy)
{
change(u << 1, tr[u].lazy);
change(u << 1 | 1, tr[u].lazy);
tr[u].lazy = 0;
}
}
void pushup(int u)
{
tr[u].sum = tr[u << 1].sum + tr[u << 1 | 1].sum;
}
void build(int u, int l, int r)
{
tr[u] = {l, r, 0, 0};
if (l == r)
{
tr[u] = {l, r, a[rk[l]], 0};
return;
}
int mid = l + r >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void modify(int u, int l, int r, int x)
{
if (tr[u].l >= l && tr[u].r <= r)
{
change(u, x);
return;
}
pushdown(u);
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid)
modify(u << 1, l, r, x);
if (r > mid)
modify(u << 1 | 1, l, r, x);
pushup(u);
}
int query(int u, int l, int r)
{
if (tr[u].l >= l && tr[u].r <= r)
{
return tr[u].sum % mod;
}
pushdown(u);
int ans = 0;
int mid = tr[u].l + tr[u].r >> 1;
if (l <= mid)
ans = (ans + query(u << 1, l, r)) % mod;
if (r > mid)
ans = (ans + query(u << 1 | 1, l, r)) % mod;
return ans;
}
void modifys(int x, int y, int c)
{
int fx = top[x], fy = top[y];
while (fx != fy) // 两点不在同一条重链
{
if (d[fx] >= d[fy]) // 先看顶点得高度,来判断lca
{
modify(1, id[fx], id[x], c);
x = f[fx], fx = top[x]; // 低点得先跳,
}
else
{
modify(1, id[fy], id[y], c);
y = f[fy], fy = top[y]; // 将x设置成原链头的父亲结点,走轻边,继续循环
}
}
// 循环结束,两点位于同一重链上,但两点不一定为同一点,所以我们还要统计这两点之间的贡献
if (id[x] <= id[y])
modify(1, id[x], id[y], c);
else
modify(1, id[y], id[x], c);
}
int sum(int x, int y)
{
int ans = 0;
int fx = top[x], fy = top[y];
while (fx != fy)
{
if (d[fx] >= d[fy])
{
ans = (ans + query(1, id[fx], id[x])) % mod;
x = f[fx], fx = top[x];
}
else
{
ans = (ans + query(1, id[fy], id[y])) % mod;
y = f[fy], fy = top[y];
}
}
if (id[x] <= id[y])
ans = (ans + query(1, id[x], id[y])) % mod;
else
ans = (ans + query(1, id[y], id[x])) % mod;
return ans;
}
void solve()
{
cin >> n >> m >> r >> mod;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n - 1; i++)
{
int a, b;
cin >> a >> b;
g[a].pb(b);
g[b].pb(a);
}
dfs1(r, 0, 1);
dfs2(r, r);
build(1, 1, n);
for (int i = 1; i <= m; i++)
{
int op, x, y, z;
cin >> op;
if (op == 1)
{
cin >> x >> y >> z;
modifys(x, y, z);
}
else if (op == 2)
{
cin >> x >> y;
cout << sum(x, y) << endl;
}
else if (op == 3)
{
cin >> x >> z;
int l = id[x];
int r = l + siz[x] - 1;
modify(1, l, r, z);
}
else
{
cin >> x;
int l = id[x];
int r = l + siz[x] - 1;
cout << query(1, l, r) % mod << endl;
}
}
}
signed main()
{
Yshanqian;
int T;
T = 1;
// cin >> T;
for (int cases = 1; cases <= T; ++cases)
{
// cout<<"Case #"<<cases<<": ";
solve();
}
return 0;
}