P3384 树链剖分模板 点权
https://www.luogu.com.cn/problem/P3384
题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
输入格式
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
输出格式
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
大概就是让你维护一棵树,要支持修改两个点之间的值同时+val,支持修改以一个点为根的子树的所有点同时+val,支持查询一条链的权值和,和一个子树的权值和。
用线段树来维护树剖之后的链。
主要记录一下自己这题为啥WA了10+发
1.没有取模
2.线段树建树的时候使用的数组应该是fp数组,即记录这个位置是哪个数字的数组。
3.在修改、查询一条链和的时候,应该比较他们的爸爸的深度,而不是比较他们自己的深度,因为两个点不在一条链上,若比较自己深度的话,可能会修改了不应该修改的权值。
#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAXN = 1e5 + 5;
int n, m, root; ll mod;
struct edge
{
int to;
int nex;
}e[MAXN * 2];
int head[MAXN], tot;
int fa[MAXN], son[MAXN], deep[MAXN], sz[MAXN];
int p[MAXN], fp[MAXN], top[MAXN], pos;
void init()
{
memset(head, -1, sizeof(head));
tot = 1;
memset(son, -1, sizeof(son));
pos = 1;
}
void add(int in, int to)
{
e[tot] = edge{ to,head[in] };
head[in] = tot++;
}
void dfs1(int u, int f, int dep)
{
fa[u] = f;
deep[u] = dep;
sz[u] = 1;
for (int i = head[u]; i + 1; i = e[i].nex)
{
int v = e[i].to;
if (v == f)
continue;
dfs1(v, u, dep + 1);
sz[u] += sz[v];
if (son[u] == -1 || sz[son[u]] < sz[v])
son[u] = v;
}
}
void dfs2(int u, int sp)
{
top[u] = sp;
p[u] = pos;
fp[pos] = u;
pos++;
if (son[u] == -1)
return;
dfs2(son[u], sp);
for (int i = head[u]; i + 1; i = e[i].nex)
{
int v = e[i].to;
if (son[u] != v && fa[u] != v)
dfs2(v, v);
}
}
//线段树
#define lson left,mid,k<<1
#define rson mid+1,right,k<<1|1
#define imid int mid=(left+right)/2;
struct node
{
int l;
int r;
ll mark;
ll sum;
}que[MAXN * 4];
ll aa[MAXN];
void up(int k)
{
que[k].sum = (que[k << 1].sum + que[k << 1 | 1].sum) % mod;
}
void down(int k)
{
if (que[k].mark)
{
que[k << 1].mark = (que[k << 1].mark + que[k].mark) % mod;
que[k << 1 | 1].mark = (que[k << 1 | 1].mark + que[k].mark) % mod;
que[k << 1].sum = (que[k << 1].sum + que[k].mark * (que[k << 1].r - que[k << 1].l + 1)) % mod;
que[k << 1 | 1].sum = (que[k << 1 | 1].sum + que[k].mark * (que[k << 1 | 1].r - que[k << 1 | 1].l + 1)) % mod;
que[k].mark = 0;
}
}
void build(int left, int right, int k)
{
que[k].l = left;
que[k].r = right;
que[k].mark = 0;
if (left == right)
{
que[k].sum = aa[fp[left]];
return;
}
imid;
build(lson);
build(rson);
up(k);
};
void update(int left, int right, int k, int ql, int qr, ll val)
{
if (qr < left || right < ql)
return;
if (ql <= left && right <= qr)
{
que[k].mark = (que[k].mark + val) % mod;
que[k].sum = (que[k].sum + (que[k].r - que[k].l + 1) * val % mod) % mod;
return;
}
down(k);
imid;
update(lson, ql, qr, val);
update(rson, ql, qr, val);
up(k);
}
ll query(int left, int right, int k, int ql, int qr)
{
if (qr < left || right < ql)
return 0;
if (ql <= left && right <= qr)
return que[k].sum;
down(k);
imid;
return (query(lson, ql, qr) + query(rson, ql, qr)) % mod;
}
//树剖
void change(int u, int v, int val)
{
int f1 = top[u], f2 = top[v];
while (f1 != f2)
{
if (deep[f1] < deep[f2])
{
swap(u, v);
swap(f1, f2);
}
update(1, n, 1, p[f1], p[u], val);
u = fa[f1];
f1 = top[u];
}
if (deep[u] > deep[v])
swap(u, v);
update(1, n, 1, p[u], p[v], val);
}
ll changes(int u, int v)
{
ll ans = 0;
int f1 = top[u], f2 = top[v];
while (f1 != f2)
{
if (deep[f1] < deep[f2])
{
swap(u, v);
swap(f1, f2);
}
ans = (ans + query(1, n, 1, p[f1], p[u])) % mod;
u = fa[f1];
f1 = top[u];
}
if (deep[u] > deep[v])
swap(u, v);
ans = (ans + query(1, n, 1, p[u], p[v])) % mod;
return ans;
}
int main()
{
sc("%d%d%d%lld", &n, &m, &root, &mod);
for (int i = 1; i <= n; i++)
{
sc("%lld", &aa[i]);
//aa[i] %= mod;
}
int a, b;
init();
for (int i = 1; i < n; i++)
{
sc("%d%d", &a, &b);
add(a, b);
add(b, a);
}
dfs1(root, 0, 1);
dfs2(root, root);
build(1, n, 1);
int op; ll val;
while (m--)
{
sc("%d", &op);
switch (op)
{
case 1:
sc("%d%d%lld", &a, &b, &val);
change(a, b, val % mod);
break;
case 2:
sc("%d%d", &a, &b);
pr("%lld\n", changes(a, b));
break;
case 3:
sc("%d%lld", &a, &val);
update(1, n, 1, p[a], p[a] + sz[a] - 1, val % mod);
break;
case 4:
sc("%d", &a);
pr("%lld\n", query(1, n, 1, p[a], p[a] + sz[a] - 1));
break;
}
}
}
/*
5 5 1 24
7 3 7 8 0
1 2
1 5
3 1
4 1
3 4 2
3 2 2
4 5
1 5 1 3
2 1 3
*/