学了2天的树链剖分终于搞懂了,不容易啊~~~~(>_<)~~~~
洛谷的3384是一道很好的模板题
传送门:https://www.luogu.org/problem/show?pid=3384#sub
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<cstdio>
#include<algorithm>
#define N 500005
using namespace std;
int n,m,R,P,x,y,z,t;
long long d[N],ee[N],real[N];
int heavyson[N],depth[N],head[N],id[N],father[N],son[N],b[N*4],c[N*4],a[N],top[N];
struct Edge{
int next,to;
}e[N];
int kk=0;
void add(int x,int y)
{
kk++;
e[kk].next=head[x];
e[kk].to=y;
head[x]=kk;
}
void build(int k,int x,int y)
{
b[k]=x; c[k]=y;
if (x==y){
d[k]=a[real[x]];
return;
}
int mid=(x+y)/2;
build(k*2,x,mid);
build(k*2+1,mid+1,y);
d[k]=d[k*2]+d[k*2+1];
}
void maintain(int k)
{
ee[k*2]=ee[k*2]+ee[k];
ee[k*2+1]=ee[k*2+1]+ee[k];
d[k*2]=d[k*2]+ee[k]*(c[k*2]-b[k*2]+1);
d[k*2+1]=d[k*2+1]+ee[k]*(c[k*2+1]-b[k*2+1]+1);
ee[k]=0;
}
long long sum(int k,int x,int y)
{
if (x==b[k]&&y==c[k]) return d[k];
if (ee[k]) maintain(k);
int mid=(b[k]+c[k])/2;
if (y<=mid) return sum(k*2,x,y);
if (x>mid) return sum(k*2+1,x,y);
if (x<=mid&&y>mid) return sum(k*2+1,mid+1,y)+sum(k*2,x,mid);
}
void addd(int k,int x,int y,int z)
{
if (x>c[k]||y<b[k]) return;
if (x<=b[k]&&y>=c[k]){
ee[k]=ee[k]+z;
d[k]=d[k]+z*(c[k]-b[k]+1);
return;
}
if (ee[k]) maintain(k);
int mid=(b[k]+c[k])/2;
if (y<=mid) addd(k*2,x,y,z);
else if (x>mid) addd(k*2+1,x,y,z);
else if (x<=mid&&y>mid){
addd(k*2,x,mid,z);
addd(k*2+1,mid+1,y,z);
}
d[k]=d[k*2]+d[k*2+1];
return;
}
void Dfs1(int now,int fa)
{
father[now]=fa;
depth[now]=depth[fa]+1;
son[now]=1;
for (int i=head[now];i;i=e[i].next){
if (e[i].to!=fa){
Dfs1(e[i].to,now);
son[now]=son[now]+son[e[i].to];
if (heavyson[now]==0||son[e[i].to]>son[heavyson[now]]) heavyson[now]=e[i].to;
}
}
}
int temp=0;
void Dfs2(int u,int first)
{
top[u]=first;
temp++;
id[u]=temp;
real[temp]=u;
if (!heavyson[u]) return;
Dfs2(heavyson[u],first);
for (int i=head[u];i;i=e[i].next){
int v=e[i].to;
if (v!=heavyson[u]&&v!=father[u]) Dfs2(v,v);
}
}
long long find(int u,int v)
{
long long sum1=0;
int tou=top[u];
int tov=top[v];
while (tou!=tov){
if (depth[tou]<depth[tov]) swap(u,v),swap(tou,tov);
sum1=sum1+sum(1,id[tou],id[u]);
sum1=sum1%P;
u=father[tou];
tou=top[u];
}
if (depth[u]>depth[v]) swap(u,v);
sum1=sum1+sum(1,id[u],id[v]);
return sum1%P;
}
void change(int u,int v,int z)
{
int tou=top[x];
int tov=top[y];
while (tou!=tov){
if (depth[tou]<depth[tov]) swap(u,v),swap(tou,tov);
addd(1,id[tou],id[u],z);
u=father[tou];
tou=top[u];
}
if (depth[u]>depth[v]) swap(u,v);
addd(1,id[u],id[v],z);
}
int main()
{
scanf("%d%d%d%d",&n,&m,&R,&P);
for (int i=1;i<=n;i++) scanf("%d",&a[i]);
for (int i=1;i<n;i++){
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
Dfs1(R,0);
Dfs2(R,R);
build(1,1,n);
for (int i=1;i<=m;i++){
scanf("%d",&t);
if (t==1){
scanf("%d%d%d",&x,&y,&z);
change(x,y,z);
}
if (t==2){
scanf("%d%d",&x,&y);
printf("%lld\n",find(x,y));
}
if (t==3){
scanf("%d%d",&x,&y);
addd(1,id[x],id[x]+son[x]-1,y);
}
if (t==4){
scanf("%d",&x);
printf("%lld\n",sum(1,id[x],id[x]+son[x]-1)%P);
}
}
return 0;
}