树链剖分模板
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210316213359600.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzQ1OTU4MzYy,size_16,color_FFFFFF,t_70)
```cpp
/*
* @Descripttion: P3384 【模板】轻重链剖分
* @Author: Fantasy_421
* @Date: 2021-03-16 19:45:27
* @LastEditTime: 2021-03-16 21:17:14
*/
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <cmath>
#define int long long
#define ull unsigned long long
#define in1(a) scanf("%d", &a)
#define in2(a, b) scanf("%d%d", &a, &b)
#define in3(a, b, c) scanf("%d%d%d", &a, &b, &c)
#define in4(a, b, c, d) scanf("%d%d%d%d", &a, &b, &c, &d)
#define in1L(a) scanf("%lld", &a)
#define in2L(a, b) scanf("%lld%lld", &a, &b)
#define in3L(a, b, c) scanf("%lld%lld%lld", &a, &b, &c)
#define in4L(a, b, c, d) scanf("%lld%lld%lld%lld", &a, &b, &c, &d)
#define IOS ios::sync_with_stdio(false), cin.tie(0), cout.tie(0)
#define rep(i, a, b) for (int i = 1; i <= a; i += b)
#define YES cout << "YES\n"
#define NO cout << "NO\n"
#define endl '\n'
using namespace std;
const int N=1e5+50;
int MOD;
int n,m,r;
int w[N],h[N],idx=1,nw[N],pos[N],size[N],son[N],dep[N],fa[N],top[N];
int id=0;
struct node
{
int ver,next;
}g[N<<1];
struct tr
{
int sum,add;
}tree[N<<2];
void add(int u,int v)
{
g[idx].ver=v;g[idx].next=h[u];h[u]=idx++;
}
void dfs(int u,int father,int depth)
{
dep[u]=depth;
size[u]=1;
fa[u]=father;
for(int i=h[u];i;i=g[i].next)
{
int ver=g[i].ver;
if(ver!=father)
{
dfs(ver,u,depth+1);
size[u]+=size[ver];
if(size[son[u]]<size[ver])
son[u]=ver;
}
}
}
void dfs(int u,int t)
{
pos[u]=++id;nw[id]=w[u];top[u]=t;
if(!son[u])
return;
dfs(son[u],t);
for(int i=h[u];i;i=g[i].next)
{
int ver=g[i].ver;
if(ver==fa[u]||ver==son[u])
continue;
dfs(ver,ver);
}
}
void pushup(int u)
{
tree[u].sum=tree[u<<1].sum+tree[u<<1|1].sum;
tree[u].sum%=MOD;
}
void pushdowm(int u,int l,int r)
{
tr &lc=tree[u<<1],&rc=tree[u<<1|1];
int mid=(l+r)>>1;
if(tree[u].add)
{
lc.add+=tree[u].add;
rc.add+=tree[u].add;
lc.add%=MOD;
rc.add%=MOD;
lc.sum+=(mid-l+1)*tree[u].add;
rc.sum+=(r-mid)*tree[u].add;
lc.sum%=MOD;
rc.sum%=MOD;
tree[u].add=0;
}
}
void build(int p,int l,int r)
{
if(l==r)
{
tree[p].sum=nw[r];
return;
}
int mid=(l+r)>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
pushup(p);
}
void update(int p,int s,int t,int L,int R,int k)
{
if(s<=L&&R<=t)
{
tree[p].add+=k;
tree[p].add%=MOD;
tree[p].sum+=(R-L+1)*k;
tree[p].sum%=MOD;
return;
}
pushdowm(p,L,R);
int mid=(L+R)>>1;
if(s<=mid)
update(p<<1,s,t,L,mid,k);
if(mid<t)
update(p<<1|1,s,t,mid+1,R,k);
pushup(p);
}
int query(int p,int s,int t,int L,int R)
{
if(s<=L&&R<=t)
{
return tree[p].sum;
}
pushdowm(p,L,R);
int res=0;
int mid=(L+R)>>1;
if(s<=mid)
{
res+=query(p<<1,s,t,L,mid);
res%=MOD;
}
if(mid<t)
{
res+=query(p<<1|1,s,t,mid+1,R);
res%=MOD;
}
return res;
}
void update_path(int u,int v,int k)
{
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
update(1,pos[top[u]],pos[u],1,n,k);
u=fa[top[u]];
}
if(dep[u]<dep[v])
swap(u,v);
update(1,pos[v],pos[u],1,n,k);
}
int query_path(int u,int v)
{
int res=0;
while(top[u]!=top[v])
{
if(dep[top[u]]<dep[top[v]])
swap(u,v);
res+=query(1,pos[top[u]],pos[u],1,n);
res%=MOD;
u=fa[top[u]];
}
if(dep[u]<dep[v])
swap(u,v);
res+=query(1,pos[v],pos[u],1,n);
res%=MOD;
return res;
}
signed main()
{
IOS;
cin>>n>>m>>r>>MOD;
for(int i=1;i<=n;i++)
{
cin>>w[i];
}
for(int i=1;i<n;i++)
{
int u,v;
cin>>u>>v;
add(u,v),add(v,u);
}
dfs(r,-1,1);
dfs(r,r);
build(1,1,n);
while(m--)
{
int t,x,y,z;
cin>>t;
if(t==1)
{
cin>>x>>y>>z;
update_path(x,y,z);
}
else if(t==2)
{
cin>>x>>y;
cout<<query_path(x,y)<<endl;
}
else if(t==3)
{
cin>>x>>z;
update(1,pos[x],pos[x]+size[x]-1,1,n,z);
}
else
{
cin>>x;
cout<<query(1,pos[x],pos[x]+size[x]-1,1,n)<<endl;
}
}
return 0;
}