題目連接配接:重鍊剖分
思路:
把樹剖分出來,然後就線段樹上修改,注意每次先修改目前節點所在鍊的頭的深度大的,然後讓它為鍊的頭的父親即可,直到兩個點,成為一條鍊上即可
#include<bits/stdc++.h>
using namespace std;
//樹鍊剖分
#define ll long long
ll n,m,rt,p,cnt,cnx;
const ll maxn=1e5+5;
ll a[maxn],head[maxn],w[maxn];
ll pre[maxn],top[maxn],sizx[maxn],son[maxn],in[maxn],deep[maxn];
struct node
{
ll to,nex;
} edge[maxn];
void add(ll u,ll v)
{
edge[cnx].to=v;
edge[cnx].nex=head[u];
head[u]=cnx++;
}
void dfs1(ll u,ll fa)
{
pre[u]=fa;
deep[u]=deep[fa]+1;
sizx[u]=1;
ll maxson=-1;
for(ll i=head[u]; ~i; i=edge[i].nex)
{
ll v=edge[i].to;
if(v!=fa)
{
dfs1(v,u);
sizx[u]+=sizx[v];
if(sizx[v]>maxson)
{
maxson=sizx[v];
son[u]=v;
}
}
}
}
void dfs2(ll u,ll t)
{
top[u]=t;
in[u]=++cnt;
w[cnt]=a[u];
if(!son[u])
return ;
dfs2(son[u],t);
for(ll i=head[u]; ~i; i=edge[i].nex)
{
ll v=edge[i].to;
if(v==son[u]||v==pre[u])
continue;
dfs2(v,v);
}
}
struct yzj
{
ll l,r,sum,lazy;
} tr[maxn*4];
void pushup(ll k)
{
tr[k].sum=(tr[k<<1].sum%p+tr[k<<1|1].sum%p)%p;
}
void pushdown(ll k)
{
if(tr[k].l==tr[k].r)
{
return;
}
if(tr[k].lazy)
{
tr[k<<1].lazy+=tr[k].lazy;
tr[k<<1|1].lazy+=tr[k].lazy;
tr[k<<1].sum+=(tr[k<<1].r-tr[k<<1].l+1)*tr[k].lazy;
tr[k<<1].sum%=p;
tr[k<<1|1].sum+=(tr[k<<1|1].r-tr[k<<1|1].l+1)*tr[k].lazy;
tr[k<<1|1].sum%=p;
tr[k].lazy=0;
}
}
void build(ll k,ll l,ll r)
{
tr[k].l=l,tr[k].r=r;
tr[k].lazy=0;
if(l==r)
{
tr[k].sum=w[l];
return ;
}
ll mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
pushup(k);
}
void modify(ll k,ll l,ll r,ll w)
{
if(tr[k].l>=l&&tr[k].r<=r)
{
tr[k].lazy+=w;
tr[k].sum+=(r-l+1)*w;
tr[k].sum%=p;
return ;
}
pushdown(k);
ll mid=tr[k].l+tr[k].r>>1;
if(mid>=r)
{
modify(k<<1,l,r,w);
}
else if(mid<l)
{
modify(k<<1|1,l,r,w);
}
else
{
modify(k<<1,l,mid,w);
modify(k<<1|1,mid+1,r,w);
}
pushup(k);
}
ll query(ll k,ll l,ll r)
{
if(tr[k].l==l&&tr[k].r==r)
{
return tr[k].sum%p;
}
pushdown(k);
ll mid=tr[k].l+tr[k].r>>1;
if(mid>=r)
{
return query(k<<1,l,r)%p;
}
else if(mid<l)
{
return query(k<<1|1,l,r)%p;
}
else
{
return (query(k<<1,l,mid)%p+query(k<<1|1,mid+1,r)%p)%p;
}
}
void opt1(ll x,ll y,ll z)
{
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
modify(1,in[top[x]],in[x],z);
x=pre[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
modify(1,in[x],in[y],z);
}
ll opt2(ll x,ll y)
{
ll res=0;
while(top[x]!=top[y])
{
if(deep[top[x]]<deep[top[y]])
swap(x,y);
res+=query(1,in[top[x]],in[x]);
res%=p;
x=pre[top[x]];
}
if(deep[x]>deep[y])
swap(x,y);
res+=query(1,in[x],in[y]);
res%=p;
return res;
}
void opt3(ll x,ll z)
{
modify(1,in[x],in[x]+sizx[x]-1,z);
}
ll opt4(ll x)
{
return query(1,in[x],in[x]+sizx[x]-1)%p;
}
int main()
{
memset(head,-1,sizeof(head));
scanf("%lld %lld %lld %lld",&n,&m,&rt,&p);
for(ll i=1; i<=n; i++)
scanf("%lld",&a[i]);
ll u,v;
for(ll i=1; i<n; i++)
{
scanf("%lld %lld",&u,&v);
add(u,v);
add(v,u);
}
dfs1(rt,0);
dfs2(rt,rt);
build(1,1,cnt);
while(m--)
{
ll op,x,y,z;
scanf("%lld",&op);
if(op==1)
{
scanf("%lld %lld %lld",&x,&y,&z);
opt1(x,y,z);
}
if(op==2)
{
scanf("%lld %lld",&x,&y);
printf("%lld\n",opt2(x,y));
}
if(op==3)
{
scanf("%lld %lld",&x,&z);
opt3(x,z);
}
if(op==4)
{
scanf("%lld",&x);
printf("%lld\n",opt4(x));
}
}
}