描述
XXX和 YYY在愉快地刷题。有一道题是这样的:给你一棵 n 个节点的有根树,每个节点有 一个权植。你要支持两种操作:查询以某棵树为根的子树的权值和,给以某个节点为根的整 棵子树的所有点的权值都加上一个值。机智的 XXX 很开心地用LLL教授 讲过的某些东西水水水水过了这道题。
但是可怕的出题人又增加了一种操作:将根节点改为第 u 号节点。于是XXX和YYY 就不会 做了。按照一惯的逻辑,这个问题被交给了你。
注意:初始时,根节点为 1 号节点,所有节点的权值都为 0。
输入
第一行有三个正整数 n, m,表示节点数和操作数。
接下来 n – 1 行每行两个正整数 p, q,表示 p 和 q 节点间有一条边。
接下来 m 行,每行首先有一个正整数 type,描述操作类型。
如果 type=1,接下来有一个正整数 u,表示询问以 u 为根的子树的权值和。
如果 type=2,接下来有两个正整数 u 和 v,表示把以 u 为根的子树的所有节点的权值都加上 v。
如果 type=3,接下来有一个正整数 u,表示把根节点改为第 u 号节点。
输出
对于每一个 1 号操作,输出一行一个非负整数表示答案。
**样例输入 **
3 4
1 2
2 3
2 2 2
1 3
3 3
1 3
样例输出
2
4
提示
【Hint】
对于 30%的数据,1 ≤ n, m ≤ 1,000。
另有 50%的数据不含有 3 号操作。
对于 100%的数据,1 ≤ n, m ≤ 200,000。
对于 100%的数据,1 ≤ u ≤ n, 1 ≤ v ≤ 500,000, 1 ≤ k ≤ n。
如果没有操作333就是一道普通的树链剖分,但加入了换根的操作,怎么办?
我们需要考虑换根对维护子树和信息的影响,那么果断分类讨论一波:
我们设当前询问的子树的根为uuu,当前的根节点为rootrootroot。
第一种情况:lcalcalca(uuu,rootrootroot)!=uuu,那么我们发现在以rootrootroot为根时uuu原来的子树就是现在的子树,直接线段树区间查询。
第二种情况:uuu==rootrootroot,那么此时uuu就是根节点,直接返回线段树根节点的maxnmaxnmaxn值
第三种情况:rootrootroot在uuu原来的子树内,即lcalcalca(rootrootroot,uuu)==uuu&&uuu!=rootrootroot,怎么做呢?
我们找到uuu在rootrootroot->uuu这条链上uuu的儿子sss,那么子树sss的补集就是我们查询的区间。
没有其他情况了。
然而这道题OJ上交会爆栈,因此写了个手工栈。
代码如下:
#include<bits/stdc++.h>
#define N 200005
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
using namespace std;
inline long long read(