dfs序:A B D G H I C E J F
用处?
就是把树强行搞成了“连续的”
我们可以发现两个重要的性质:
一个结点的子树上的结点的时间戳,一定大于这个结点的时间戳且连续
某些链上的时间戳也是连续的
那么对于操作3,4,就可以套一个线段树实现了
把树看成数组,时间戳是下标,结点的值为当前下标的值
a[1] = 'A', a[2] = 'B', a[7] = 'C'
操作3:将以x为根结点的子树内所有结点值都加上z
操作4:求以x为根节点的子树内所有结点值值和
那么,操作1和操作2怎么搞呢?并不是所有链都是连续的时间戳啊
这时候我们就需要树链剖分大法
然后利用线段树解决问题
开始剖分:
跑一边dfs,标记以下内容:
结点的父亲是谁
结点的重儿子是谁
结点的深度
结点的大小
可是没有标记时间戳啊,因为我们要先知道结点的重儿子是谁,才能开始标记时间戳,所以呢,再跑一遍dfs,标记以下内容;
结点权值的dfs序与时间戳
当前结点所在重链的头是谁,头的头就是自己
const int maxn = 1e5 + 5;
const int maxm = maxn * 2;
struct E{
int to, next;
}Edge[maxm];
int tot, Head[maxn];//Head数组初始化为-1而不是0
inline void AddEdge(int u, int v){
Edge[tot] = (E){v, Head[u]};
Head[u] = tot++;
Edge[tot] = (E){u, Head[v]};
Head[v] = tot++;
}
int fa[maxn], dep[maxn], siz[maxn], son[maxn];
void dfs1(int u, int f){
fa[u] = f;
dep[u] = dep[f] + 1;
siz[u] = 1;
int maxsize = -1;//判断是不是重儿子的临时变量
for(int i = Head[u]; ~i; i = Edge[i].next){
int v = Edge[i].to;
if(v == f) continue;
dfs1(v, u);
siz[u] += siz[v];
if(siz[v] > maxsize){
maxsize = siz[v];
son[u] = v;
}
}
}
int tim, dfn[maxn], top[maxn],w[maxn], v[maxn];
void dfs2(int u, int t){
dfn[u] = ++tim;
top[u] = t;
w[tim] = v[u];
if(!son[u]) return;
dfs2(son[u], t);
for(int i = Head[u]; ~i; i = Edge[i].next){
int v = Edge[i].to;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
线段树:就不写了
操作3:将以x为根节点的子树内所有结点值都加上z
操作4:求以x为根节点的子树内所有节点值之和
inline void mson(int x, int z){
modify(dfn[x], dfn[x] + siz[x] - 1, z);
}
inline int qson(int x){
return query(dfn[x], dfn[x] + siz[x] - 1);
}
引理:除了根结点外的任何一个结点的父亲结点都一定在一条重链上
证明:因为父亲结点存在儿子,所以一定存在重儿子,所以一定在一条重链上
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
const int maxm = maxn * 2;
int v[maxn];
struct E
{
int to, next;
} Edge[maxm];
int tot, Head[maxn];
inline void AddEdge(int u, int v)
{
Edge[tot] = (E){v, Head[u]};
Head[u] = tot++;
Edge[tot] = (E){u, Head[v]};
Head[v] = tot++;
}
int mod;
int fa[maxn], dep[maxn], siz[maxn], son[maxn];
void dfs1(int u, int f)
{
fa[u] = f;
dep[u] = dep[f] + 1;
siz[u] = 1;
int maxsize = -1;
for (int i = Head[u]; ~i; i = Edge[i].next)
{
int v = Edge[i].to;
if (v == f)
continue;
dfs1(v, u);
siz[u] += siz[v];
if (siz[v] > maxsize)
{
maxsize = siz[v];
son[u] = v;
}
}
}
int tim, dfn[maxn], top[maxn], w[maxn];
void dfs2(int u, int t){
dfn[u] = ++tim;
top[u] = t;
w[tim] = v[u];
if(!son[u]) return;
dfs2(son[u], t);
for(int i = Head[u]; ~i; i = Edge[i].next){
int v = Edge[i].to;
if(v == fa[u] || v == son[u]) continue;
dfs2(v, v);
}
}
struct node{
int l, r, f, val;
}sgt[maxn * 4];
inline int ls(int k){return k << 1;}
inline int rs(int k){return k << 1 | 1;}
inline void pushup(int k){ sgt[k].val = (sgt[ls(k)].val + sgt[rs(k)].val) % mod;}
inline void pushdown(int k){
sgt[ls(k)].f += sgt[k].f;
sgt[rs(k)].f += sgt[k].f;
sgt[ls(k)].val += (sgt[ls(k)].r - sgt[ls(k)].l + 1) * sgt[k].f % mod;
sgt[rs(k)].val += (sgt[rs(k)].r - sgt[rs(k)].l + 1) * sgt[k].f % mod;
sgt[k].f = 0;
}
void build(int l, int r, int k = 1){
sgt[k].l = l, sgt[k].r = r;
if(l == r){
sgt[k].val = w[l] % mod;
return;
}
int m = (l + r) >> 1;
build(l, m, ls(k));
build(m + 1, r, rs(k));
pushup(k);
}
void modify(int x, int y, int z, int k = 1){
int l = sgt[k].l, r = sgt[k].r;
if(x <= l && y >= r){
sgt[k].f += z;
sgt[k].val += (r - l + 1) * z;
sgt[k].val %= mod;
return;
}
if(sgt[k].f) pushdown(k);
int m = (l + r) >> 1;
if(x <= m) modify(x, y, z, ls(k));
if(y > m) modify(x, y, z, rs(k));
pushup(k);
}
int query(int x, int y, int k = 1){
int l = sgt[k].l, r = sgt[k].r;
if(x <= l && y >= r) return sgt[k].val;
if(sgt[k].f) pushdown(k);
int sum = 0, m = (l + r) >> 1;
if(x <= m) sum += query(x, y, ls(k));
if(y > m) sum += query(x, y, rs(k));
return sum % mod;
}
inline void mson(int x, int z){
modify(dfn[x], dfn[x] + siz[x] - 1, z);
}
inline int qson(int x){
return query(dfn[x], dfn[x] + siz[x] - 1);
}
void mchain(int x, int y, int z){
z %= mod;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
modify(dfn[top[x]], dfn[x], z);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
modify(dfn[x], dfn[y], z);
}
int qchain(int x, int y){
int ret = 0;
while(top[x] != top[y]){
if(dep[top[x]] < dep[top[y]]) swap(x, y);
ret += query(dfn[top[x]], dfn[x]);
x = fa[top[x]];
}
if(dep[x] > dep[y]) swap(x, y);
ret += query(dfn[x], dfn[y]);
return ret % mod;
}
void print(int x){
cout << x << "\n";
}
int main(){
memset(Head, -1, sizeof(Head));
int n, m, r;
cin >> n >> m >> r >> mod;
for(int i = 1; i <= n; i++){
cin >> v[i];
}
for(int i = 1; i < n; i++){
int u, v;
cin >> u >> v;
AddEdge(u, v);
}
dfs1(r, r);
dfs2(r, r);
build(1, n);
while(m--){
int opt, x, y ,z;
cin >> opt;
switch(opt){
case 1:
cin >> x >> y >> z;
mchain(x, y ,z);
break;
case 2:
cin >> x >> y;
print(qchain(x, y));
break;
case 3:
cin >> x >> z;
mson(x, z);
break;
case 4:
cin >> x;
print(qson(x));
break;
}
}
return 0;
}