【一本通提高树链剖分】「ZJOI2008」树的统计

[ZJOI2008]树的统计

题目描述

一棵树上有 n n n 个节点,编号分别为 1 1 1 n n n,每个节点都有一个权值 w w w

我们将以下面的形式来要求你对这棵树完成一些操作:

I. CHANGE u t : 把结点 u u u 的权值改为 t t t

II. QMAX u v: 询问从点 u u u 到点 v v v 的路径上的节点的最大权值。

III. QSUM u v: 询问从点 u u u 到点 v v v 的路径上的节点的权值和。

注意:从点 u u u 到点 v v v 的路径上的节点包括 u u u v v v 本身。

输入格式

输入文件的第一行为一个整数 n n n,表示节点的个数。

接下来 n − 1 n-1 n1 行,每行 2 2 2 个整数 a a a b b b,表示节点 a a a 和节点 b b b 之间有一条边相连。

接下来一行 n n n 个整数,第 i i i 个整数 w i w_i wi 表示节点 i i i 的权值。

接下来 1 1 1 行,为一个整数 q q q,表示操作的总数。

接下来 q q q 行,每行一个操作,以 CHANGE u t 或者 QMAX u v 或者 QSUM u v 的形式给出。

输出格式

对于每个 QMAX 或者 QSUM 的操作,每行输出一个整数表示要求输出的结果。

输入输出样例

样例输入1
4
1 2
2 3
4 1
4 2 1 3
12
QMAX 3 4
QMAX 3 3
QMAX 3 2
QMAX 2 3
QSUM 3 4
QSUM 2 1
CHANGE 1 5
QMAX 3 4
CHANGE 3 6
QMAX 3 4
QMAX 2 4
QSUM 3 4
样例输出1
4
1
2
2
10
6
5
6
5
16

说明/提示

对于 100 % 100 \% 100% 的数据,保证 1 ≤ n ≤ 3 × 1 0 4 1\le n \le 3\times 10^4 1n3×104 0 ≤ q ≤ 2 × 1 0 5 0\le q\le 2\times 10^5 0q2×105

中途操作中保证每个节点的权值 w w w − 3 × 1 0 4 -3\times 10^4 3×104 3 × 1 0 4 3\times 10^4 3×104 之间。

Code

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast")
#include <bits/stdc++.h>
using namespace std;
const int N = 30005;
stack<int>s;
int n, m, q;
char ch[10];
struct lct
{
	int fa, c[2], rev, val, sm, mx;
	inline int &operator[] (int x)
	{
		return c[x];
	}
} t[N];
void pushup(int x)
{
	int ls = t[x][0], rs = t[x][1];
	t[x].sm = t[ls].sm + t[rs].sm + t[x].val;
	t[x].mx = max(max(t[ls].mx, t[rs].mx), t[x].val);
}
void pushdown(int x)
{
	int ls = t[x][0], rs = t[x][1];
	if (t[x].rev)
		t[ls].rev ^= 1, t[rs].rev ^= 1,swap(t[x][0], t[x][1]), t[x].rev = 0;
}
bool pdrt(int x)
{
	return t[t[x].fa][0] != x && t[t[x].fa][1] != x;
}
void rotate(int x)
{
	int y = t[x].fa, z = t[y].fa, dy = (t[y][1] == x), dz = (t[z][1] == y);
	if (!pdrt(y))
		t[z][dz] = x;
	t[y][dy] = t[x][dy ^ 1], t[t[x][dy ^ 1]].fa = y;
	t[x][dy ^ 1] = y, t[y].fa = x, t[x].fa = z;
	pushup(y);
}
void splay(int x)
{
	s.push(x);
	for (int i = x; !pdrt(i); i = t[i].fa)
		s.push(t[i].fa);
	while (s.size())
		pushdown(s.top()), s.pop();
	while (!pdrt(x))
	{
		int y = t[x].fa;
		int z = t[y].fa;
		if (!pdrt(y))
			if (t[y][1] == x ^ t[z][1] == y)
				rotate(x);
			else
				rotate(y);
		rotate(x);
	}
	pushup(x);
}
void access(int x)
{
	for (int i = 0; x; x = t[x].fa)
		splay(x), t[x][1] = i, i = x;
}
void mkrt(int x)
{
	access(x), splay(x), t[x].rev ^= 1;
}
int main()
{
	scanf("%d", &n);
	t[0].mx = -99999;
	for (int i = 1, x, y; i < n; i++)
		scanf("%d%d", &x, &y), mkrt(x), t[x].fa = y;
	for (int i = 1; i <= n; i++)
		splay(i),
		      scanf("%d", &t[i].val), pushup(i);
	scanf("%d", &q);
	while (q--)
	{
		int x, y;
		scanf("%s%d%d", ch, &x, &y);
		if (ch[1] == 'H')
			splay(x),
			      t[x].val = y, pushup(x);
		else if (ch[1] == 'M')
		{
			mkrt(x);
			access(y);
			splay(y);
			printf("%d\n", t[y].mx);
		}
		else
		{
			mkrt(x);
			access(y);
			splay(y);
			printf("%d\n", t[y].sm);
		}
	}
	return 0;
}

广告

绿树公司 - 官方网站:https://wangping-lvshu.github.io/LvshuNew/

绿树智能 - 官方网站:https://wangping-lvshu.github.io/LvshuZhineng/

(现在使用,人人均可获得300元大奖)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lvshu · 绿树

非常感谢您的搭讪

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值