题目中出现的树链剖分一般分为两种,重链剖分和长链剖分
重剖主要用于维护子树信息和链信息,长剖主要用于维护子树中只与深度有关的信息
子树的 d f s dfs dfs序是连续的
树上的子树修改和子树查询,等价于 d f s dfs dfs序上的区间修改和区间查询
树划分为轻边和重链
重链上的点dfs序连续,可以数据结构维护
轻边的两端点一定分属某条重链上的点
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
//depp为节点深度,n_size为节点大小,fa为节点父亲,son为节点的重儿子
void dfs1(int now, int f, int depth) { //now当前节点,f父亲,depth深度
deep[now] = depth; //标记每个点的深度
fa[now] = f; //标记每个点的父亲
n_size[now] = 1; //标记每个非叶子节点的子树大小
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue; //若为父亲则continue
dfs1(edge[i].v, now, depth + 1); //dfs其儿子
n_size[now] += n_size[edge[i].v]; //把它的儿子数加到它身上
if (n_size[edge[i].v] > n_size[son[now]])//标记每个非叶子节点的重儿子编号
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn; //链的顶点,节点的dfs序,dfs序编号
//int wt[maxn], w[maxn]; //新的点权值,原点的权值
void dfs2(int now, int top_node) { //now当前节点,top_node当前链的最顶端的节点
id[now] = ++dfn; //标记每个点的新编号
//wt[dfn] = w[now]; //把每个点的初始值赋到新编号上来
top[now] = top_node; //这个点所在链的顶端
if (!son[now]) return; //如果没有儿子则返回
dfs2(son[now], top_node); //按先处理重儿子,再处理轻儿子的顺序递归处理
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v); //对于每一个轻儿子都有一条从它自己开始的链
}
}
深度大的点跳到上一条链
直到两点跳到同一条链为止
int lca(int x, int y) { //x,y为树上两点编号
for (; top[x] != top[y]; x = fa[top[x]])//若不在一个链上,跳转这条链
if (deep[top[x]] < deep[top[y]]) //先跳转深度深的点
swap(x, y);
return deep[x] < deep[y] ? x : y; //在同一条链上返回深度深的点
}
重复y找祖先的过程,记录上个链的头
若祖先为一个链的尾节点,返回上个链的头
否则返回重儿子即可
int lca2(int x, int y) { //计算y的祖先x向y的第一个点
int t; //记录上个链的顶点
while (top[x] != top[y]) //y向上个链跳转
t = top[y], y = fa[top[y]];
return x == y ? t : son[x]; //x==y则返回上个链的头,反之返回重儿子即可
}
重复寻找LCA的过程,处理每个链即可
void chain(int x, int y, int val) { //x,y为树上两点编号,val操作
for (; top[x] != top[y]; x = fa[top[x]]) { //若不在一个链上,计算这条链
if (deep[top[x]] < deep[top[y]])swap(x, y); //先计算深度深的点
op(id[top[x]], id[x], val); //调用线段树操作
}
if (deep[x] < deep[y])swap(x, y); //在一条链上
op(id[y], id[x], val); //调用线段树操作
}
边权转点权版
void chain(int x, int y, int val) { //x,y为树上两点编号,val操作
for (; top[x] != top[y]; x = fa[top[x]]) { //若不在一个链上,计算这条链
if (deep[top[x]] < deep[top[y]])swap(x, y); //先计算深度深的点
op(id[top[x]], id[x], val); //调用线段树操作
}
if (deep[x] < deep[y])swap(x, y); //在一条链上
op(id[y]+1, id[x], val); //调用线段树操作,若x==y,线段树不会出问题,不然要调用lca2,抛去lca
}
LL tree[maxn << 2], lazy[maxn << 2];
void build(int root, int left, int right) { //建树
if (left == right) {
tree[root] = wt[left];
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = (tree[root << 1]+ tree[root << 1 | 1]) % mod;
}
void pushdown(int root, int left, int right) { //懒标记
if (!lazy[root]) return;
int mid = (left + right) >> 1;
tree[root << 1] = (tree[root << 1] + (LL(mid) - left + 1) * lazy[root] % mod) % mod;
lazy[root << 1] = (lazy[root << 1] + lazy[root]) % mod;
tree[root << 1 | 1] = (tree[root << 1 | 1] + (LL(right) - mid) * lazy[root] % mod) % mod;
lazy[root << 1 | 1] = (lazy[root << 1 | 1] + lazy[root]) % mod;
lazy[root] = 0;
}
void update(int root, int left, int right, int stdl, int stdr, LL val) { //区间加
if (stdl <= left && right <= stdr) {
tree[root] = (tree[root] + (LL(right) - left + 1) * val % mod);
lazy[root] = (lazy[root] + val) % mod;
return;
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) update(root << 1, left, mid, stdl, stdr, val);
if (stdr > mid) update(root << 1 | 1, mid + 1, right, stdl, stdr, val);
tree[root] = (tree[root << 1] + tree[root << 1 | 1]) % mod;
}
LL query(int root, int left, int right, int stdl, int stdr) { //区间求和
LL ans = 0;
if (stdl <= left && right <= stdr)
return tree[root];
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) ans = (ans + query(root << 1, left, mid, stdl, stdr)) % mod;
if (stdr > mid) ans = (ans + query(root << 1 | 1, mid + 1, right, stdl, stdr)) % mod;
return ans;
}
代码附于文末
调用lca函数即可
调用上方链操作即可
void chainadd(int x, int y, int val) { //x,y为树上两点编号,val操作
for (; top[x] != top[y]; x = fa[top[x]]) { //若不在一个链上,计算这条链
if (deep[top[x]] < deep[top[y]])swap(x, y); //先计算深度深的点
update(1, 1, n, id[top[x]], id[x], val); //区间加
}
if (deep[x] < deep[y])swap(x, y); //在一条链上
update(1, 1, n, id[y], id[x], val); //区间加
}
LL chainsum(int x, int y) { //x,y为树上两点编号,val操作
LL res = 0;
for (; top[x] != top[y]; x = fa[top[x]]) { //若不在一个链上,计算这条链
if (deep[top[x]] < deep[top[y]])swap(x, y); //先计算深度深的点
res = (res + query(1, 1, n, id[top[x]], id[x])) % mod; //区间求和
}
if (deep[x] < deep[y])swap(x, y); //在一条链上
res = (res + query(1, 1, n, id[y], id[x])) % mod; //区间求和
return res;
}
子树的 d f s dfs dfs序是连续的
树上的子树修改和子树查询,等价于 d f s dfs dfs序上的区间修改和区间查询
update(1, 1, n, id[x], id[x] + n_size[x] - 1, z);//子树修改
query(1, 1, n, id[x], id[x] + n_size[x] - 1); //子树求和
题意:
两个操作,1、将某条边由1变成0,2、将1到x求和
思路:
边权转点权
由点权表示该点上一条边的边权
根无点权
修改:将深度大的点变为0
查询:对1到x求和
直接树链剖分+树状数组即可
代码附于文末
同上题
有几个注意点
1、将根的min设为inf,max设为-inf而不是0
2、求链的操作时,lca的权值不能加进去
代码附于文末
题意:
两个操作: 1 x 1 x 1x求s到x的路径和并将s变成x 2 x w 2 x w 2xw将x号边变成w
思路:
边权转点权的裸题
代码附于文末
题意:
3个操作: 1 x 1 x 1x将根换成x, 2 x y v 2 x y v 2xyv将 x − y x-y x−y变成v, 3 x 3 x 3x求x的子树的最小值
思路:
换根
如果当前数据指定的根在查询的子树内
则查询操作变为查询根所在分支的子树外的点 (调用 lca2)
可以由两个区间( 1 − i d [ x ] − 1 1-id[x]-1 1−id[x]−1和 i d [ x ] + s i z e [ x ] − n id[x]+size[x]-n id[x]+size[x]−n)最小值合并得到
如果根在子树外,直接查询子树即可
代码附于文末
题意:
2个操作: C h a n g e x y z Change x y z Changexyz将x到y的链变成z, Q u e r y x y Query x y Queryxy求x到y的链上的不同的连续数的个数,比如 11221 11221 11221有三个
思路:
边权转点权
注意剖去lca
链合并带有方向性
int chain_query(int x, int y) {
int prex = -1, prey = -1, res = 0; //记录两个点的前端点
Tree T;
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]]) {
swap(x, y);
swap(prex, prey);
}
T = query(1, 1, n, id[top[x]], id[x]);
res += T.data;
if (T.suf == prex)res--;
prex = T.pre;
}
if (deep[x] < deep[y]) {
swap(x, y);
swap(prex, prey);
}
if (x == y) { //特判lca为重链最后一个点时
if (prex == prey)res--;
return res;
}
T = query(1, 1, n, id[y] + 1, id[x]);
res += T.data;
if (prex == T.suf)res--;
if (prey == T.pre)res--;
return res;
}
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int maxn = 100005;
const int maxm = 100005;
const LL mod = 1e9;
int head[maxn], tot;
struct Edge
{
int v;
int next;
}edge[maxm << 1];
void init() {
memset(head, 0, sizeof(head));
tot = 0;
}
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
void dfs1(int now, int f, int depth) {
deep[now] = depth;
fa[now] = f;
n_size[now] = 1;
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue;
dfs1(edge[i].v, now, depth + 1);
n_size[now] += n_size[edge[i].v];
if (n_size[edge[i].v] > n_size[son[now]])
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn;
int wt[maxn], w[maxn];
void dfs2(int now, int top_node) {
id[now] = ++dfn;
wt[dfn] = w[now];
top[now] = top_node;
if (!son[now]) return;
dfs2(son[now], top_node);
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v);
}
}
int lca(int x, int y) {
for (; top[x] != top[y]; x = fa[top[x]])
if (deep[top[x]] < deep[top[y]])
swap(x, y);
return deep[x] < deep[y] ? x : y;
}
int lca2(int x, int y) {
int t;
while (top[x] != top[y])
t = top[y], y = fa[top[y]];
return x == y ? t : son[x];
}
LL tree[maxn << 2], lazy[maxn << 2];
void build(int root, int left, int right) {
if (left == right) {
tree[root] = wt[left];
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
void pushdown(int root, int left, int right) {
if (!lazy[root]) return;
int mid = (left + right) >> 1;
tree[root << 1] = tree[root << 1] + (LL(mid) - left + 1) * lazy[root];
lazy[root << 1] = lazy[root << 1] + lazy[root];
tree[root << 1 | 1] = tree[root << 1 | 1] + (LL(right) - mid) * lazy[root];
lazy[root << 1 | 1] = lazy[root << 1 | 1] + lazy[root];
lazy[root] = 0;
}
void update(int root, int left, int right, int stdl, int stdr, LL val) {
if (stdl <= left && right <= stdr) {
tree[root] = tree[root] + (LL(right) - left + 1) * val;
lazy[root] = lazy[root] + val;
return;
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) update(root << 1, left, mid, stdl, stdr, val);
if (stdr > mid) update(root << 1 | 1, mid + 1, right, stdl, stdr, val);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
LL query(int root, int left, int right, int stdl, int stdr) {
LL ans = 0;
if (stdl <= left && right <= stdr)
return tree[root];
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) ans = ans + query(root << 1, left, mid, stdl, stdr);
if (stdr > mid) ans = ans + query(root << 1 | 1, mid + 1, right, stdl, stdr);
return ans;
}
void chain(int x, int y, int val) {
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
op(id[top[x]], id[x], val);
}
if (deep[x] < deep[y])swap(x, y);
op(id[y], id[x], val);
}
#include
#include
#include
#include
using namespace std;
typedef long long LL;
const int maxn = 100005;
const int maxm = 100005;
int n, m, s;
LL mod;
int head[maxn], tot;
struct Edge
{
int v;
int next;
}edge[maxm << 1];
void init() {
memset(head, 0, sizeof(head));
tot = 0;
}
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
//depp为节点深度,n_size为节点大小,fa为节点父亲,son为节点的重儿子
void dfs1(int now, int f, int depth) { //now当前节点,f父亲,depth深度
deep[now] = depth; //标记每个点的深度
fa[now] = f; //标记每个点的父亲
n_size[now] = 1; //标记每个非叶子节点的子树大小
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue; //若为父亲则continue
dfs1(edge[i].v, now, depth + 1); //dfs其儿子
n_size[now] += n_size[edge[i].v]; //把它的儿子数加到它身上
if (n_size[edge[i].v] > n_size[son[now]])//标记每个非叶子节点的重儿子编号
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn; //链的顶点,节点的dfs序,dfs序编号
LL wt[maxn], w[maxn]; //新的点权值,原点的权值
void dfs2(int now, int top_node) { //now当前节点,top_node当前链的最顶端的节点
id[now] = ++dfn; //标记每个点的新编号
wt[dfn] = w[now]; //把每个点的初始值赋到新编号上来
top[now] = top_node; //这个点所在链的顶端
if (!son[now]) return; //如果没有儿子则返回
dfs2(son[now], top_node); //按先处理重儿子,再处理轻儿子的顺序递归处理
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v); //对于每一个轻儿子都有一条从它自己开始的链
}
}
LL tree[maxn << 2], lazy[maxn << 2];
void build(int root, int left, int right) {
if (left == right) {
tree[root] = wt[left];
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = (tree[root << 1]+ tree[root << 1 | 1]) % mod;
}
void pushdown(int root, int left, int right) {
if (!lazy[root]) return;
int mid = (left + right) >> 1;
tree[root << 1] = (tree[root << 1] + (LL(mid) - left + 1) * lazy[root] % mod) % mod;
lazy[root << 1] = (lazy[root << 1] + lazy[root]) % mod;
tree[root << 1 | 1] = (tree[root << 1 | 1] + (LL(right) - mid) * lazy[root] % mod) % mod;
lazy[root << 1 | 1] = (lazy[root << 1 | 1] + lazy[root]) % mod;
lazy[root] = 0;
}
void update(int root, int left, int right, int stdl, int stdr, LL val) {
if (stdl <= left && right <= stdr) {
tree[root] = (tree[root] + (LL(right) - left + 1) * val % mod);
lazy[root] = (lazy[root] + val) % mod;
return;
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) update(root << 1, left, mid, stdl, stdr, val);
if (stdr > mid) update(root << 1 | 1, mid + 1, right, stdl, stdr, val);
tree[root] = (tree[root << 1] + tree[root << 1 | 1]) % mod;
}
LL query(int root, int left, int right, int stdl, int stdr) {
LL ans = 0;
if (stdl <= left && right <= stdr)
return tree[root];
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) ans = (ans + query(root << 1, left, mid, stdl, stdr)) % mod;
if (stdr > mid) ans = (ans + query(root << 1 | 1, mid + 1, right, stdl, stdr)) % mod;
return ans;
}
void chain1(int x, int y, int val) { //x,y为树上两点编号,val操作
for (; top[x] != top[y]; x = fa[top[x]]) { //若不在一个链上,计算这条链
if (deep[top[x]] < deep[top[y]])swap(x, y); //先计算深度深的点
update(1, 1, n, id[top[x]], id[x], val); //调用线段树操作
}
if (deep[x] < deep[y])swap(x, y); //在一条链上
update(1, 1, n, id[y], id[x], val); //调用线段树操作
}
LL chain2(int x, int y) { //x,y为树上两点编号,val操作
LL res = 0;
for (; top[x] != top[y]; x = fa[top[x]]) { //若不在一个链上,计算这条链
if (deep[top[x]] < deep[top[y]])swap(x, y); //先计算深度深的点
res = (res + query(1, 1, n, id[top[x]], id[x])) % mod; //调用线段树操作
}
if (deep[x] < deep[y])swap(x, y); //在一条链上
res = (res + query(1, 1, n, id[y], id[x])) % mod; //调用线段树操作
return res;
}
int main() {
scanf("%d%d%d%lld", &n, &m, &s, &mod);
for (int i = 1; i <= n; i++)
scanf("%lld", &w[i]);
int u, v;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
AddEdge(u, v);
AddEdge(v, u);
}
dfs1(s, 0, 1);
dfs2(s, s);
build(1, 1, n);
int g, x, y; LL z;
while (m--) {
scanf("%d", &g);
if (g == 1) {
scanf("%d%d%lld", &x, &y, &z);
z %= mod;
chain1(x, y, z);
}
else if (g == 2) {
scanf("%d%d", &x, &y);
printf("%lld\n", chain2(x, y));
}
else if (g == 3) {
scanf("%d%lld", &x, &z);
z %= mod;
update(1, 1, n, id[x], id[x] + n_size[x] - 1, z);
}
else {
scanf("%d", &x);
printf("%lld\n", query(1, 1, n, id[x], id[x] + n_size[x] - 1));
}
}
}
#include
#include
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
typedef pair<int, int> pii;
const int maxn = 30005;
const int maxm = 30005;
const int inf = 0X3f3f3f3f;
const int mod = 1e9+7;
int n, q;
int head[maxn], tot;
struct Edge
{
int v;
int next;
}edge[maxm << 1];
void init() {
memset(head, 0, sizeof(head));
tot = 0;
}
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
//depp为节点深度,n_size为节点大小,fa为节点父亲,son为节点的重儿子
void dfs1(int now, int f, int depth) { //now当前节点,f父亲,depth深度
deep[now] = depth; //标记每个点的深度
fa[now] = f; //标记每个点的父亲
n_size[now] = 1; //标记每个非叶子节点的子树大小
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue; //若为父亲则continue
dfs1(edge[i].v, now, depth + 1); //dfs其儿子
n_size[now] += n_size[edge[i].v]; //把它的儿子数加到它身上
if (n_size[edge[i].v] > n_size[son[now]])//标记每个非叶子节点的重儿子编号
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn; //链的顶点,节点的dfs序,dfs序编号
int wt[maxn], w[maxn]; //新的点权值,原点的权值
void dfs2(int now, int top_node) { //now当前节点,top_node当前链的最顶端的节点
id[now] = ++dfn; //标记每个点的新编号
wt[dfn] = w[now]; //把每个点的初始值赋到新编号上来
top[now] = top_node; //这个点所在链的顶端
if (!son[now]) return; //如果没有儿子则返回
dfs2(son[now], top_node); //按先处理重儿子,再处理轻儿子的顺序递归处理
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v); //对于每一个轻儿子都有一条从它自己开始的链
}
}
pii tree[maxn << 2];
void build(int root, int left, int right) {
if (left == right) {
tree[root].first = wt[left];
tree[root].second = wt[left];
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root].first = tree[root << 1].first + tree[root << 1 | 1].first;
tree[root].second = max(tree[root << 1].second, tree[root << 1 | 1].second);
}
void update(int root, int left, int right, int x, int val) {
if (left == right) {
tree[root].first = tree[root].second = val;
return;
}
int mid = (left + right) >> 1;
if (x <= mid) update(root << 1, left, mid, x, val);
else update(root << 1 | 1, mid + 1, right, x, val);
tree[root].first = (tree[root << 1].first + tree[root << 1 | 1].first);
tree[root].second = max(tree[root << 1].second, tree[root << 1 | 1].second);
}
int query_first(int root, int left, int right, int stdl, int stdr) {
int ans = 0;
if (stdl <= left && right <= stdr)
return tree[root].first;
int mid = (left + right) >> 1;
if (stdl <= mid) ans = (ans + query_first(root << 1, left, mid, stdl, stdr));
if (stdr > mid) ans = (ans + query_first(root << 1 | 1, mid + 1, right, stdl, stdr));
return ans;
}
int query_second(int root, int left, int right, int stdl, int stdr) {
int ans = -inf;
if (stdl <= left && right <= stdr)
return tree[root].second;
int mid = (left + right) >> 1;
if (stdl <= mid) ans = max(ans, query_second(root << 1, left, mid, stdl, stdr));
if (stdr > mid) ans = max(ans, query_second(root << 1 | 1, mid + 1, right, stdl, stdr));
return ans;
}
int chain_first(int x, int y) { //x,y为树上两点编号,val操作
int res = 0;
for (; top[x] != top[y]; x = fa[top[x]]) { //若不在一个链上,计算这条链
if (deep[top[x]] < deep[top[y]])swap(x, y); //先计算深度深的点
res += query_first(1, 1, n, id[top[x]], id[x]); //调用线段树操作
}
if (deep[x] < deep[y])swap(x, y); //在一条链上
res += query_first(1, 1, n, id[y], id[x]); //调用线段树操作
return res;
}
int chain_second(int x, int y) { //x,y为树上两点编号,val操作
int res = -inf;
for (; top[x] != top[y]; x = fa[top[x]]) { //若不在一个链上,计算这条链
if (deep[top[x]] < deep[top[y]])swap(x, y); //先计算深度深的点
res = max(res, query_second(1, 1, n, id[top[x]], id[x])); //调用线段树操作
}
if (deep[x] < deep[y])swap(x, y); //在一条链上
res = max(res, query_second(1, 1, n, id[y], id[x])); //调用线段树操作
return res;
}
int main() {
scanf("%d", &n);
int u, v;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
AddEdge(u, v);
AddEdge(v, u);
}
for (int i = 1; i <= n; i++)
scanf("%d", &w[i]);
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, 1, n);
char s[10];
int x;
int m; scanf("%d", &m);
while (m--) {
scanf("%s", s);
if (s[0] == 'C') {
scanf("%d%d", &x, &v);
update(1, 1, n, id[x], v);
}
else if (s[1] == 'S') {
scanf("%d%d", &u, &v);
printf("%d\n", chain_first(u, v));
}
else {
scanf("%d%d", &u, &v);
printf("%d\n", chain_second(u, v));
}
}
}
#include
#include
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 200005;
const int maxm = 200005;
int n;
int head[maxn], tot;
struct Edge
{
int v;
int next;
}edge[maxm << 1];
void init() {
memset(head, 0, sizeof(head));
tot = 0;
}
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
//depp为节点深度,n_size为节点大小,fa为节点父亲,son为节点的重儿子
void dfs1(int now, int f, int depth) { //now当前节点,f父亲,depth深度
deep[now] = depth; //标记每个点的深度
fa[now] = f; //标记每个点的父亲
n_size[now] = 1; //标记每个非叶子节点的子树大小
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue; //若为父亲则continue
dfs1(edge[i].v, now, depth + 1); //dfs其儿子
n_size[now] += n_size[edge[i].v]; //把它的儿子数加到它身上
if (n_size[edge[i].v] > n_size[son[now]])//标记每个非叶子节点的重儿子编号
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn; //链的顶点,节点的dfs序,dfs序编号
int wt[maxn], w[maxn]; //新的点权值,原点的权值
void dfs2(int now, int top_node) { //now当前节点,top_node当前链的最顶端的节点
id[now] = ++dfn; //标记每个点的新编号
wt[dfn] = w[now]; //把每个点的初始值赋到新编号上来
top[now] = top_node; //这个点所在链的顶端
if (!son[now]) return; //如果没有儿子则返回
dfs2(son[now], top_node); //按先处理重儿子,再处理轻儿子的顺序递归处理
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v); //对于每一个轻儿子都有一条从它自己开始的链
}
}
int tree[maxn << 2], lazy[maxn << 2];
void build(int root, int left, int right) {
if (left == right) {
tree[root] = 0;
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
void pushdown(int root, int left, int right) {
if (lazy[root] == -1) return;
int mid = (left + right) >> 1;
tree[root << 1] = (mid - left + 1) * lazy[root];
tree[root << 1 | 1] = (right - mid) * lazy[root];
lazy[root << 1] = lazy[root << 1 | 1] = lazy[root];
lazy[root] = -1;
}
void update(int root, int left, int right, int stdl, int stdr, int val) {
if (stdl <= left && right <= stdr) {
tree[root] = (right - left + 1) * val;
lazy[root] = val;
return;
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) update(root << 1, left, mid, stdl, stdr, val);
if (stdr > mid) update(root << 1 | 1, mid + 1, right, stdl, stdr, val);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
int query(int root, int left, int right, int stdl, int stdr) {
int ans = 0;
if (stdl <= left && right <= stdr)
return tree[root];
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) ans = (ans + query(root << 1, left, mid, stdl, stdr));
if (stdr > mid) ans = (ans + query(root << 1 | 1, mid + 1, right, stdl, stdr)) ;
return ans;
}
void chain_update(int x, int y, int val) {
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
update(1, 1, n, id[top[x]], id[x], val);
}
if (deep[x] < deep[y])swap(x, y);
update(1, 1, n, id[y], id[x], val);
}
int chain_query(int x, int y) {
int res = 0;
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
res += query(1, 1, n, id[top[x]], id[x]);
}
if (deep[x] < deep[y])swap(x, y);
res += query(1, 1, n, id[y], id[x]);
return res;
}
int main() {
memset(lazy, -1, sizeof(lazy));
scanf("%d", &n);
int u, v;
for (int i = 2; i <= n; i++) {
scanf("%d", &v);
AddEdge(i, v + 1);
AddEdge(v + 1, i);
}
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, 1, n);
int q; scanf("%d", &q);
char s[11]; int x, sum = 0, cnt;
while (q--) {
scanf("%s", s);
scanf("%d", &x); x++;
if (s[0] == 'i') {
chain_update(1, x, 1);
cnt = query(1, 1, n, 1, n);
printf("%d\n", cnt - sum);
sum = cnt;
}
else {
update(1, 1, n, id[x], id[x] + n_size[x] - 1, 0);
cnt = query(1, 1, n, 1, n);
printf("%d\n", sum - cnt);
sum = cnt;
}
}
}
#include
#include
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 250005;
const int maxm = 250005;
const LL mod = 1e9;
const int inf = 0X3f3f3f3f;
int n;
int head[maxn], tot;
struct Edge
{
int v;
int next;
}edge[maxm << 1];
void init() {
memset(head, 0, sizeof(head));
tot = 0;
}
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
//depp为节点深度,n_size为节点大小,fa为节点父亲,son为节点的重儿子
void dfs1(int now, int f, int depth) { //now当前节点,f父亲,depth深度
deep[now] = depth; //标记每个点的深度
fa[now] = f; //标记每个点的父亲
n_size[now] = 1; //标记每个非叶子节点的子树大小
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue; //若为父亲则continue
dfs1(edge[i].v, now, depth + 1); //dfs其儿子
n_size[now] += n_size[edge[i].v]; //把它的儿子数加到它身上
if (n_size[edge[i].v] > n_size[son[now]])//标记每个非叶子节点的重儿子编号
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn; //链的顶点,节点的dfs序,dfs序编号
int wt[maxn], w[maxn]; //新的点权值,原点的权值
void dfs2(int now, int top_node) { //now当前节点,top_node当前链的最顶端的节点
id[now] = ++dfn; //标记每个点的新编号
wt[dfn] = w[now]; //把每个点的初始值赋到新编号上来
top[now] = top_node; //这个点所在链的顶端
if (!son[now]) return; //如果没有儿子则返回
dfs2(son[now], top_node); //按先处理重儿子,再处理轻儿子的顺序递归处理
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v); //对于每一个轻儿子都有一条从它自己开始的链
}
}
int tree[maxn];
inline int lowbit(int x) {
return x & -x;
}
void update(int x, int v) {
while (x <= n) {
tree[x] += v;
x += lowbit(x);
}
}
int query(int x) {
int res = 0;
while (x) {
res += tree[x];
x -= lowbit(x);
}
return res;
}
int chain(int x, int y) {
int res = 0;
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
res += query(id[x]) - query(id[top[x]] - 1);
}
if (deep[x] < deep[y])swap(x, y);
res += query(id[x]) - query(id[y] - 1);
return res;
}
int main() {
scanf("%d", &n);
w[1] = 0;
for (int i = 2; i <= n; i++)w[i] = 1;
int u, v;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
AddEdge(u, v);
AddEdge(v, u);
}
dfs1(1, 0, 1);
dfs2(1, 1);
for (int i = 1; i <= n; i++)
update(id[i], wt[i]);
int m; scanf("%d", &m);
m += n - 1;
char s[10];
while (m--) {
scanf("%s", s);
if (s[0] == 'W') {
scanf("%d", &v);
printf("%d\n", chain(1, v));
}
else {
scanf("%d%d", &u, &v);
if (deep[u] > deep[v])swap(u, v);
update(id[v], -1);
}
}
}
#include
#include
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 20005;
const int maxm = 20005;
const int inf = 0X3f3f3f3f;
int n;
int head[maxn], tot;
struct Edge {
int v;
int next;
} edge[maxm << 1];
void init() {
memset(head, 0, sizeof(head));
tot = 0;
}
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
//depp为节点深度,n_size为节点大小,fa为节点父亲,son为节点的重儿子
void dfs1(int now, int f, int depth) { //now当前节点,f父亲,depth深度
deep[now] = depth; //标记每个点的深度
fa[now] = f; //标记每个点的父亲
n_size[now] = 1; //标记每个非叶子节点的子树大小
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue; //若为父亲则continue
dfs1(edge[i].v, now, depth + 1); //dfs其儿子
n_size[now] += n_size[edge[i].v]; //把它的儿子数加到它身上
if (n_size[edge[i].v] > n_size[son[now]])//标记每个非叶子节点的重儿子编号
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn; //链的顶点,节点的dfs序,dfs序编号
int wt[maxn], w[maxn]; //新的点权值,原点的权值
void dfs2(int now, int top_node) { //now当前节点,top_node当前链的最顶端的节点
id[now] = ++dfn; //标记每个点的新编号
wt[dfn] = w[now]; //把每个点的初始值赋到新编号上来
top[now] = top_node; //这个点所在链的顶端
if (!son[now]) return; //如果没有儿子则返回
dfs2(son[now], top_node); //按先处理重儿子,再处理轻儿子的顺序递归处理
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v); //对于每一个轻儿子都有一条从它自己开始的链
}
}
struct Tree {
int data;
int max;
int min;
} tree[maxn << 2];
int lazy[maxn << 2];
void build(int root, int left, int right) {
lazy[root] = 1;
if (left == right) {
tree[root].data = tree[root].max = tree[root].min = wt[left];
if (left == 1)tree[root].max = -inf, tree[root].min = inf;
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root].data = tree[root << 1].data + tree[root << 1 | 1].data;
tree[root].max = max(tree[root << 1].max, tree[root << 1 | 1].max);
tree[root].min = min(tree[root << 1].min, tree[root << 1 | 1].min);
}
void pushdown(int root, int left, int right) {
if (lazy[root] == 1) return;
int mid = (left + right) >> 1;
swap(tree[root << 1].max, tree[root << 1].min);
swap(tree[root << 1 | 1].max, tree[root << 1 | 1].min);
tree[root << 1].data = -tree[root << 1].data;
tree[root << 1 | 1].data = -tree[root << 1 | 1].data;
tree[root << 1].min = -tree[root << 1].min;
tree[root << 1 | 1].min = -tree[root << 1 | 1].min;
tree[root << 1].max = -tree[root << 1].max;
tree[root << 1 | 1].max = -tree[root << 1 | 1].max;
lazy[root << 1] = -lazy[root << 1];
lazy[root << 1 | 1] = -lazy[root << 1 | 1];
lazy[root] = 1;
}
void update(int root, int left, int right, int stdl, int stdr) {
if (stdl <= left && right <= stdr) {
swap(tree[root].max, tree[root].min);
tree[root].data = -tree[root].data;
tree[root].max = -tree[root].max;
tree[root].min = -tree[root].min;
lazy[root] = -lazy[root];
return;
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) update(root << 1, left, mid, stdl, stdr);
if (stdr > mid) update(root << 1 | 1, mid + 1, right, stdl, stdr);
tree[root].data = tree[root << 1].data + tree[root << 1 | 1].data;
tree[root].max = max(tree[root << 1].max, tree[root << 1 | 1].max);
tree[root].min = min(tree[root << 1].min, tree[root << 1 | 1].min);
}
void modify(int root, int left, int right, int x, int val) {
if (left == right) {
tree[root].data = tree[root].max = tree[root].min = val;
return;
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (x <= mid) modify(root << 1, left, mid, x, val);
else modify(root << 1 | 1, mid + 1, right, x, val);
tree[root].data = tree[root << 1].data + tree[root << 1 | 1].data;
tree[root].max = max(tree[root << 1].max, tree[root << 1 | 1].max);
tree[root].min = min(tree[root << 1].min, tree[root << 1 | 1].min);
}
int query_sum(int root, int left, int right, int stdl, int stdr) {
int ans = 0;
if (stdl <= left && right <= stdr)
return tree[root].data;
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) ans = ans + query_sum(root << 1, left, mid, stdl, stdr);
if (stdr > mid) ans = ans + query_sum(root << 1 | 1, mid + 1, right, stdl, stdr);
return ans;
}
int query_max(int root, int left, int right, int stdl, int stdr) {
if (stdl <= left && right <= stdr)
return tree[root].max;
pushdown(root, left, right);
int mid = (left + right) >> 1, ans = -inf;
if (stdl <= mid) ans = max(ans, query_max(root << 1, left, mid, stdl, stdr));
if (stdr > mid) ans = max(ans, query_max(root << 1 | 1, mid + 1, right, stdl, stdr));
return ans;
}
int query_min(int root, int left, int right, int stdl, int stdr) {
if (stdl <= left && right <= stdr)
return tree[root].min;
pushdown(root, left, right);
int mid = (left + right) >> 1, ans = inf;
if (stdl <= mid) ans = min(ans, query_min(root << 1, left, mid, stdl, stdr));
if (stdr > mid) ans = min(ans, query_min(root << 1 | 1, mid + 1, right, stdl, stdr));
return ans;
}
void chain_update(int x, int y) {
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
update(1, 1, n, id[top[x]], id[x]);
}
if (deep[x] < deep[y])swap(x, y);
update(1, 1, n, id[y] + 1, id[x]);
}
int chain_sum(int x, int y) {
int res = 0;
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
res += query_sum(1, 1, n, id[top[x]], id[x]);
}
if (deep[x] < deep[y])swap(x, y);
res += query_sum(1, 1, n, id[y] + 1, id[x]);
return res;
}
int chain_max(int x, int y) {
int res = -inf;
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
res = max(res, query_max(1, 1, n, id[top[x]], id[x]));
}
if (deep[x] < deep[y])swap(x, y);
res = max(res, query_max(1, 1, n, id[y] + 1, id[x]));
return res;
}
int chain_min(int x, int y) {
int res = inf;
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
res = min(res, query_min(1, 1, n, id[top[x]], id[x]));
}
if (deep[x] < deep[y])swap(x, y);
res = min(res, query_min(1, 1, n, id[y] + 1, id[x]));
return res;
}
int u[maxn], v[maxn], s[maxn];
int main() {
scanf("%d", &n);
for (int i = 1; i < n; i++) {
scanf("%d%d%d", &u[i], &v[i], &s[i]);
u[i]++;
v[i]++;
AddEdge(u[i], v[i]);
AddEdge(v[i], u[i]);
}
dfs1(1, 0, 1);
for (int i = 1; i < n; i++) {
if (deep[u[i]] > deep[v[i]]) swap(u[i], v[i]);
w[v[i]] = s[i];
}
dfs2(1, 1);
build(1, 1, n);
for (int i = 1; i <= 3; i++)
cout << wt[i] << ' ';
cout << '\n';
cout << query_max(1, 1, n, 2, 1);
int m;
scanf("%d", &m);
char s[10];
int x, y, z;
while (m--) {
scanf("%s", s);
if (s[0] == 'C') {
scanf("%d%d", &x, &z);
modify(1, 1, n, id[v[x]], z);
}
else if (s[0] == 'N') {
scanf("%d%d", &x, &y);
x++;
y++;
chain_update(x, y);
}
else if (s[0] == 'S') {
scanf("%d%d", &x, &y);
x++;
y++;
printf("%d\n", chain_sum(x, y));
}
else if (s[1] == 'A') {
scanf("%d%d", &x, &y);
x++;
y++;
printf("%d\n", chain_max(x, y));
}
else {
scanf("%d%d", &x, &y);
x++;
y++;
printf("%d\n", chain_min(x, y));
}
}
}
#include
#include
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 100005;
const int maxm = 100005;
const LL mod = 1e9;
int n, q, s;
int head[maxn], tot;
struct Edge
{
int v;
int next;
}edge[maxm << 1];
void init() {
memset(head, 0, sizeof(head));
tot = 0;
}
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
void dfs1(int now, int f, int depth) {
deep[now] = depth;
fa[now] = f;
n_size[now] = 1;
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue;
dfs1(edge[i].v, now, depth + 1);
n_size[now] += n_size[edge[i].v];
if (n_size[edge[i].v] > n_size[son[now]])
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn;
int wt[maxn], w[maxn];
void dfs2(int now, int top_node) {
id[now] = ++dfn;
wt[dfn] = w[now];
top[now] = top_node;
if (!son[now]) return;
dfs2(son[now], top_node);
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v);
}
}
int tree[maxn << 2], lazy[maxn << 2];
void build(int root, int left, int right) {
if (left == right) {
tree[root] = wt[left];
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
void update(int root, int left, int right, int x, int val) {
if (left == right) {
tree[root] = val;
return;
}
int mid = (left + right) >> 1;
if (x <= mid) update(root << 1, left, mid, x, val);
else update(root << 1 | 1, mid + 1, right, x, val);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
int query(int root, int left, int right, int stdl, int stdr) {
int ans = 0;
if (stdl <= left && right <= stdr)
return tree[root];
int mid = (left + right) >> 1;
if (stdl <= mid) ans = ans + query(root << 1, left, mid, stdl, stdr);
if (stdr > mid) ans = ans + query(root << 1 | 1, mid + 1, right, stdl, stdr);
return ans;
}
int chain_query(int x, int y) {
int res = 0;
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
res += query(1, 1, n, id[top[x]], id[x]);
}
if (deep[x] < deep[y])swap(x, y);
res += query(1, 1, n, id[y] + 1, id[x]);
return res;
}
int u[maxn], v[maxn], p[maxn];
int main() {
scanf("%d%d%d", &n, &q, &s);
for (int i = 1; i < n; i++) {
scanf("%d%d%d", &u[i], &v[i], &p[i]);
AddEdge(u[i], v[i]);
AddEdge(v[i], u[i]);
}
dfs1(1, 0, 1);
for (int i = 1; i < n; i++) {
if (deep[u[i]] > deep[v[i]]) swap(u[i], v[i]);
w[v[i]] = p[i];
}
dfs2(1, 1);
build(1, 1, n);
int opt, x, y, z;
while (q--) {
scanf("%d", &opt);
if (opt == 0) {
scanf("%d", &x);
printf("%d\n", chain_query(s, x));
s = x;
}
else {
scanf("%d%d", &x, &z);
update(1, 1, n, id[v[x]], z);
}
}
}
#include
#include
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 100005;
const int maxm = 100005;
const LL inf = 1e18;
int n, m;
int head[maxn], tot;
struct Edge
{
int v;
int next;
}edge[maxm << 1];
void init() {
memset(head, 0, sizeof(head));
tot = 0;
}
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
//depp为节点深度,n_size为节点大小,fa为节点父亲,son为节点的重儿子
void dfs1(int now, int f, int depth) { //now当前节点,f父亲,depth深度
deep[now] = depth; //标记每个点的深度
fa[now] = f; //标记每个点的父亲
n_size[now] = 1; //标记每个非叶子节点的子树大小
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue; //若为父亲则continue
dfs1(edge[i].v, now, depth + 1); //dfs其儿子
n_size[now] += n_size[edge[i].v]; //把它的儿子数加到它身上
if (n_size[edge[i].v] > n_size[son[now]])//标记每个非叶子节点的重儿子编号
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn; //链的顶点,节点的dfs序,dfs序编号
LL wt[maxn], w[maxn]; //新的点权值,原点的权值
void dfs2(int now, int top_node) { //now当前节点,top_node当前链的最顶端的节点
id[now] = ++dfn; //标记每个点的新编号
wt[dfn] = w[now]; //把每个点的初始值赋到新编号上来
top[now] = top_node; //这个点所在链的顶端
if (!son[now]) return; //如果没有儿子则返回
dfs2(son[now], top_node); //按先处理重儿子,再处理轻儿子的顺序递归处理
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v); //对于每一个轻儿子都有一条从它自己开始的链
}
}
int lca2(int x, int y) { //计算y的祖先x向y的第一个点
int t; //记录上个链的顶点
while (top[x] != top[y]) //y向上个链跳转
t = top[y], y = fa[top[y]];
return x == y ? t : son[x]; //x==y则返回上个链的头,反之返回重儿子即可
}
LL tree[maxn << 2], lazy[maxn << 2];
void build(int root, int left, int right) {
if (left == right) {
tree[root] = wt[left];
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = min(tree[root << 1], tree[root << 1 | 1]);
}
void pushdown(int root, int left, int right) {
if (lazy[root] == -1) return;
int mid = (left + right) >> 1;
tree[root << 1] = tree[root << 1 | 1] = lazy[root];
lazy[root << 1] = lazy[root << 1 | 1] = lazy[root];
lazy[root] = -1;
}
void update(int root, int left, int right, int stdl, int stdr, LL val) {
if (stdl <= left && right <= stdr) {
tree[root] = val;
lazy[root] = val;
return;
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) update(root << 1, left, mid, stdl, stdr, val);
if (stdr > mid) update(root << 1 | 1, mid + 1, right, stdl, stdr, val);
tree[root] = min(tree[root << 1], tree[root << 1 | 1]);
}
LL query(int root, int left, int right, int stdl, int stdr) {
if (stdl <= left && right <= stdr)
return tree[root];
pushdown(root, left, right);
LL ans = inf;
int mid = (left + right) >> 1;
if (stdl <= mid) ans = min(ans, query(root << 1, left, mid, stdl, stdr));
if (stdr > mid) ans = min(ans, query(root << 1 | 1, mid + 1, right, stdl, stdr));
return ans;
}
void chain_modify(int x, int y, int val) {
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
update(1, 1, n, id[top[x]], id[x], val);
}
if (deep[x] < deep[y])swap(x, y);
update(1, 1, n, id[y], id[x], val);
}
int main() {
memset(lazy, -1, sizeof(lazy));
scanf("%d%d", &n, &m);
int u, v; LL val;
for (int i = 1; i < n; i++) {
scanf("%d%d", &u, &v);
AddEdge(u, v);
AddEdge(v, u);
}
for (int i = 1; i <= n; i++)
scanf("%lld", &w[i]);
dfs1(1, 0, 1);
dfs2(1, 1);
build(1, 1, n);
int rt, opt; scanf("%d", &rt);
while (m--) {
scanf("%d", &opt);
if (opt == 1) scanf("%d", &rt);
else if (opt == 2) {
scanf("%d%d", &u, &v);
scanf("%lld", &val);
chain_modify(u, v, val);
}
else {
scanf("%d", &u);
if (rt == u) {
printf("%lld\n", query(1, 1, n, 1, n));
}
else if (id[rt] >= id[u] && id[rt] <= id[u] + n_size[u] - 1) {
int clo_id = lca2(u, rt);
printf("%lld\n", min(query(1, 1, n, 1, id[clo_id] - 1), query(1, 1, n, id[clo_id] + n_size[clo_id], n)));
}
else
printf("%lld\n", query(1, 1, n, id[u], id[u] + n_size[u] - 1));
}
}
}
#include
#include
#include
#include
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 40005;
const int maxm = 40005;
const LL mod = 1e9;
int n, m;
int head[maxn], tot;
struct Edge {
int v;
int next;
} edge[maxm << 1];
inline void AddEdge(int u, int v) {
edge[++tot].v = v;
edge[tot].next = head[u];
head[u] = tot;
}
int deep[maxn], n_size[maxn], fa[maxn], son[maxn];
//depp为节点深度,n_size为节点大小,fa为节点父亲,son为节点的重儿子
void dfs1(int now, int f, int depth) { //now当前节点,f父亲,depth深度
deep[now] = depth; //标记每个点的深度
fa[now] = f; //标记每个点的父亲
n_size[now] = 1; //标记每个非叶子节点的子树大小
for (int i = head[now]; i; i = edge[i].next) {
if (f == edge[i].v)continue; //若为父亲则continue
dfs1(edge[i].v, now, depth + 1); //dfs其儿子
n_size[now] += n_size[edge[i].v]; //把它的儿子数加到它身上
if (n_size[edge[i].v] > n_size[son[now]])//标记每个非叶子节点的重儿子编号
son[now] = edge[i].v;
}
}
int top[maxn], id[maxn], dfn; //链的顶点,节点的dfs序,dfs序编号
int wt[maxn], w[maxn]; //新的点权值,原点的权值
void dfs2(int now, int top_node) { //now当前节点,top_node当前链的最顶端的节点
id[now] = ++dfn; //标记每个点的新编号
wt[dfn] = w[now]; //把每个点的初始值赋到新编号上来
top[now] = top_node; //这个点所在链的顶端
if (!son[now]) return; //如果没有儿子则返回
dfs2(son[now], top_node); //按先处理重儿子,再处理轻儿子的顺序递归处理
for (int i = head[now]; i; i = edge[i].next) {
if (edge[i].v == fa[now] || edge[i].v == son[now])continue;
dfs2(edge[i].v, edge[i].v); //对于每一个轻儿子都有一条从它自己开始的链
}
}
struct Tree {
int pre;
int suf;
int data;
Tree() {
pre = suf = data = -1;
}
friend Tree operator +(const Tree& a, const Tree& b) {
if (a.data == -1)return b;
if (b.data == -1) return a;
Tree res;
res.pre = a.pre;
res.suf = b.suf;
if (a.suf == b.pre)res.data = a.data + b.data - 1;
else res.data = a.data + b.data;
return res;
}
} tree[maxn << 2];
int lazy[maxn << 2];
void build(int root, int left, int right) {
lazy[root] = -1;
if (left == right) {
tree[root].pre = tree[root].suf = wt[left];
tree[root].data = 1;
return;
}
int mid = (left + right) >> 1;
build(root << 1, left, mid);
build(root << 1 | 1, mid + 1, right);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
void pushdown(int root, int left, int right) {
if (lazy[root] == -1) return;
int mid = (left + right) >> 1;
tree[root << 1].data = 1;
tree[root << 1].pre = tree[root << 1].suf = lazy[root];
tree[root << 1 | 1].data = 1;
tree[root << 1 | 1].pre = tree[root << 1 | 1].suf = lazy[root];
lazy[root << 1] = lazy[root << 1 | 1] = lazy[root];
lazy[root] = -1;
}
void update(int root, int left, int right, int stdl, int stdr, int val) {
if (stdl <= left && right <= stdr) {
tree[root].data = 1;
tree[root].pre = tree[root].suf = val;
lazy[root] = val;
return;
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
if (stdl <= mid) update(root << 1, left, mid, stdl, stdr, val);
if (stdr > mid) update(root << 1 | 1, mid + 1, right, stdl, stdr, val);
tree[root] = tree[root << 1] + tree[root << 1 | 1];
}
Tree query(int root, int left, int right, int stdl, int stdr) {
if (stdl <= left && right <= stdr) {
return tree[root];
}
pushdown(root, left, right);
int mid = (left + right) >> 1;
Tree lson, rson;
if (stdl <= mid) lson = query(root << 1, left, mid, stdl, stdr);
if (stdr > mid) rson = query(root << 1 | 1, mid + 1, right, stdl, stdr);
return lson + rson;
}
void chain_update(int x, int y, int val) {
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]])swap(x, y);
update(1, 1, n, id[top[x]], id[x], val);
}
if (deep[x] < deep[y])swap(x, y);
update(1, 1, n, id[y] + 1, id[x], val);
}
int chain_query(int x, int y) {
int prex = -1, prey = -1, res = 0;
Tree T;
for (; top[x] != top[y]; x = fa[top[x]]) {
if (deep[top[x]] < deep[top[y]]) {
swap(x, y);
swap(prex, prey);
}
T = query(1, 1, n, id[top[x]], id[x]);
res += T.data;
if (T.suf == prex)res--;
prex = T.pre;
}
if (deep[x] < deep[y]) {
swap(x, y);
swap(prex, prey);
}
if (x == y) {
if (prex == prey)res--;
return res;
}
T = query(1, 1, n, id[y] + 1, id[x]);
res += T.data;
if (prex == T.suf)res--;
if (prey == T.pre)res--;
return res;
}
void init() {
fill(head, head + 1 + n, 0);
fill(son, son + 1 + n, 0);
tot = 0;
dfn = 0;
}
int u[maxn], v[maxn], s[maxn];
int main() {
while (~scanf("%d%d", &n, &m)) {
init();
for (int i = 1; i < n; i++) {
scanf("%d%d%d", &u[i], &v[i], &s[i]);
AddEdge(u[i], v[i]);
AddEdge(v[i], u[i]);
}
dfs1(1, 0, 1);
w[1] = -1;
for (int i = 1; i < n; i++) {
if (deep[u[i]] > deep[v[i]])
swap(u[i], v[i]);
w[v[i]] = s[i];
}
dfs2(1, 1);
build(1, 1, n);
int x, y, z;
char opt[10];
while (m--) {
scanf("%s", opt);
if (opt[0] == 'C') {
scanf("%d%d%d", &x, &y, &z);
chain_update(x, y, z);
}
else {
scanf("%d%d", &x, &y);
printf("%d\n", x == y ? 0 : chain_query(x, y));
}
}
}
}