Lindone @ 2023-03-26 19:57:15
#include <bits/stdc++.h>
using namespace std;
#define Ls (X << 1)
#define Rs (Ls | 1)
#define MAXN 100005
#define MAXEG 200005
struct Link
{
int Y, Next;
}Graph[MAXEG];
int Nume, Head[MAXN];
int N, M, R, P;
void AddLink(int X, int Y)
{
Graph[++Nume].Y = Y;
Graph[Nume].Next = Head[X];
Head[X] = Nume;
}
int A[MAXN], Val[MAXN];
struct SegmentTree
{
int Sum[4 * MAXN], Tag[4 * MAXN];
void Pushup(int X)
{
Sum[X] = (Sum[Ls] + Sum[Rs]) % P;
}
void Pushdown(int X, int L, int R)
{
int Mid = (L + R) >> 1;
Tag[Ls] = (Tag[Ls] + Tag[X]) % P;
Tag[Rs] = (Tag[Rs] + Tag[X]) % P;
Sum[Ls] = (Sum[Ls] + Tag[X] * (Mid - L + 1)) % P;
Sum[Rs] = (Sum[Rs] + Tag[X] * (R - Mid) % P) % P;
Tag[X] = 0;
}
void BuildTree(int X, int L, int R)
{
if (L == R)
{
Sum[X] = Val[L];
return;
}
int Mid = (L + R) >> 1;
BuildTree(Ls, L, Mid);
BuildTree(Rs, Mid + 1, R);
Pushup(X);
}
int QueryTree(int X, int L, int R, int Start, int End)
{
if (R < Start || End < L) return 0;
if (Start <= L && R <= End)
{
return Sum[X];
}
Pushdown(X, L, R);
int Mid = (L + R) >> 1;
return (QueryTree(Ls, L, Mid, Start, End) + QueryTree(Rs, Mid + 1, R, Start, End)) % P;
}
void UpdateTree(int X, int L, int R, int Start, int End, int K)
{
if (R < Start || End < L) return;
if (Start <= L && R <= End)
{
Tag[X] = (Tag[X] + K) % P;
Sum[X] = (Sum[X] + K * (R - L + 1) % P) % P;
return;
}
Pushdown(X, L, R);
int Mid = (L + R) >> 1;
UpdateTree(Ls, L, Mid, Start, End, K);
UpdateTree(Rs, Mid + 1, R, Start, End, K);
Pushup(X);
}
void Build()
{
BuildTree(1, 1, N);
}
int Query(int Start, int End)
{
return QueryTree(1, 1, N, Start, End);
}
void Update(int Start, int End, int K)
{
UpdateTree(1, 1, N, Start, End, K);
}
}Tree;
struct TreeChain
{
int Time, DFN[MAXN], Son[MAXN], Size[MAXN], Depth[MAXN], Top[MAXN], Father[MAXN];
void DFS1(int X, int Fa)
{
Size[X] = 1;
Father[X] = Fa;
Depth[X] = Depth[Fa] + 1;
for (int i = Head[X]; i; i = Graph[i].Next)
{
int& Y = Graph[i].Y;
if (Y == Fa)
continue;
DFS1(Y, X);
Size[X] += Size[Y];
if (Size[Son[X]] < Size[Y])
Son[X] = Y;
}
}
void DFS2(int X, int TopV)
{
Top[X] = TopV;
Val[++Time] = A[X];
DFN[X] = Time;
if (!Son[X]) return;
DFS2(Son[X], TopV);
for (int i = Head[X]; i; i = Graph[i].Next)
{
int& Y = Graph[i].Y;
if (Y == Father[X])
continue;
DFS2(Y, Y);
}
}
void Initial()
{
DFS1(R, 0);
DFS2(R, R);
Tree.Build();
}
int Query(int X, int Y)
{
int Ans = 0;
while (Top[X] != Top[Y])
{
if (Depth[Top[X]] < Depth[Top[Y]])
swap(X, Y);
Ans = (Ans + Tree.Query(DFN[Top[X]], DFN[X]) % P) % P;
X = Father[Top[X]];
}
if (Depth[X] > Depth[Y])
swap(X, Y);
Ans = (Ans + Tree.Query(DFN[X], DFN[Y]) % P) % P;
return Ans;
}
void Update(int X, int Y, int K)
{
while (Top[X] != Top[Y])
{
if (Depth[Top[X]] < Depth[Top[Y]])
swap(X, Y);
Tree.Update(DFN[Top[X]], DFN[X], K);
X = Father[Top[X]];
}
if (Depth[X] > Depth[Y])
swap(X, Y);
Tree.Update(DFN[X], DFN[Y], K);
}
int QueryRoot(int X)
{
return Tree.Query(DFN[X], DFN[X] + Size[X] - 1);
}
void UpdateRoot(int X, int K)
{
Tree.Update(DFN[X], DFN[X] + Size[X] - 1, K);
}
}Obj;
int main()
{
cin >> N >> M >> R >> P;
for (int i = 1; i <= N; ++i)
{
cin >> A[i];
}
int U, V;
for (int i = 1; i < N; ++i)
{
cin >> U >> V;
AddLink(U, V);
AddLink(V, U);
}
Obj.Initial();
int Op, X, Y, Z;
for (int i = 1; i <= M; ++i)
{
cin >> Op >> X;
if (Op == 1)
{
cin >> Y >> Z;
Obj.Update(X, Y, Z);
}
if (Op == 2)
{
cin >> Y;
cout << Obj.Query(X, Y) << endl;
}
if (Op == 3)
{
cin >> Z;
Obj.UpdateRoot(X, Z);
}
if (Op == 4)
{
cout << Obj.QueryRoot(X) << endl;
}
}
return 0;
}
by forgotmyhandle @ 2023-03-26 20:15:57
DFS2 里把重儿子算了两遍。
for 循环里的 if 应该是
if (Y == Father[X] || Y == son[X])
continue;
但是你没写 || 右边。
by forgotmyhandle @ 2023-03-26 20:18:12
(如此毒瘤的数据结构写挂了居然真还有人帮忙看(笑
by Lindone @ 2023-04-23 22:00:45
@forgotmyhandle 才看到,谢谢。。。