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
*/