树链剖分就是将树上的点通过轻重链剖分来将其合理地(即时间复杂度令人满意)hash成一个线段,之后再用线段树来维护。
也可以想象成将树上最长的链拿出来,短的链就在旁边填填补补这种感觉?
详细讲的话,像我这种蒟蒻肯定是讲不好的,各种分析也不会,丢个代码直接细软跑好了。
hashh是正向hash。
hashv是反向hash,致敬韦神。
#include
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
#define pa pair
const int maxn=500010;
const int INF=1e9+7;
using namespace std;
/*----------------------------------------------------------------------------*/
inline ll read()
{
char ls;ll x=0,sng=1;
for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
return x*sng;
}
/*----------------------------------------------------------------------------*/
ll n,m,root,mod;
struct kaga
{
int next;
int point;
}e[maxn];
struct akagi
{
int l,r;
ll sum,lazy;
}tr[maxn];
int last[maxn],k=0,fa[maxn],size[maxn],son[maxn],belong[maxn],hashh[maxn],hashv[maxn],dep[maxn],v[maxn];
void sumup(int x)
{
tr[x].sum=(tr[x<<1].sum+tr[x<<1|1].sum)%mod;
return ;
}
void pushdown(int x)
{
int y=tr[x].lazy;
if(y)
{
tr[x<<1].lazy+=y;
tr[x<<1].sum+=(tr[x<<1].r-tr[x<<1].l+1)*y;
tr[x<<1|1].lazy+=y;
tr[x<<1|1].sum+=(tr[x<<1|1].r-tr[x<<1|1].l+1)*y;
tr[x].lazy=0;
}
return ;
}
void build(int x,int l,int r)
{
int mid=(l+r)>>1;
tr[x].l=l;tr[x].r=r;
if(l==r)
{
tr[x].sum=v[hashv[l]];
tr[x].lazy=0;
return ;
}
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
sumup(x);
return ;
}
void change(int x,int L,int R,int val)
{
int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;
if(L<=l&&r<=R)
{
tr[x].lazy+=val;tr[x].lazy%=mod;
tr[x].sum+=val*(r-l+1);tr[x].sum%=mod;
return ;
}
pushdown(x);
if(R<=mid)change(x<<1,L,R,val);
else if(L>mid)change(x<<1|1,L,R,val);
else change(x<<1,L,mid,val),change(x<<1|1,mid+1,R,val);
sumup(x);
return ;
}
ll query(int x,int L,int R)
{
int l=tr[x].l,r=tr[x].r,mid=(l+r)>>1;
if(L<=l&&r<=R)return tr[x].sum;
pushdown(x);
if(R<=mid)query(x<<1,L,R);
else if(L>mid)query(x<<1|1,L,R);
else return (query(x<<1,L,mid)+query(x<<1|1,mid+1,R))%mod;
}
void add_edge(int x,int y)
{
e[++k].next=y;e[k].point=last[x];last[x]=k;
}
void insert(int x,int y)
{
add_edge(x,y);
add_edge(y,x);
}
void dfs1(int x,int fat)
{
fa[x]=fat;
dep[x]=dep[fat]+1;
size[x]=1;
for(int j=last[x];j;j=e[j].point)
{
int y=e[j].next;
if(y==fat)continue;
dfs1(y,x);
size[x]+=size[y];
if(!son[x]||size[y]>size[son[x]])
son[x]=y;
}
}
void dfs2(int x,int top)
{
belong[x]=top;
hashh[x]=++k;
hashv[k]=x;
if(!son[x])return ;
dfs2(son[x],top);
for(int j=last[x];j;j=e[j].point)
{
int y=e[j].next;
if(y!=son[x]&&y!=fa[x])
dfs2(y,y);
}
}
void update(int x,int y,int val)
{
int topx=belong[x];
int topy=belong[y];
while(topx!=topy)
{
if(dep[topx]x,y);
swap(topx,topy);
}
change(1,hashh[topx],hashh[x],val);
x=fa[topx];
topx=belong[x];
}
if(dep[x]>dep[y])swap(x,y);
change(1,hashh[x],hashh[y],val);
}
ll sigma(int x,int y)
{
ll sum=0;
int topx=belong[x];
int topy=belong[y];
while(topx!=topy)
{
if(dep[topx]x,y);
swap(topx,topy);
}
sum+=query(1,hashh[topx],hashh[x]);
sum%=mod;
x=fa[topx];
topx=belong[x];
}
if(dep[x]>dep[y])swap(x,y);
sum+=query(1,hashh[x],hashh[y]);
return sum%mod;
}
void updateson(int x,int val)
{
int left=hashh[x];
int right=hashh[x]+size[x]-1;
change(1,left,right,val);
}
ll sigmason(int x)
{
int left=hashh[x];
int right=hashh[x]+size[x]-1;
return query(1,left,right)%mod;
}
int main()
{
n=read();m=read();root=read();mod=read();
fer(i,1,n)v[i]=read();
fer(i,1,n-1)
{
int x=read(),y=read();
insert(x,y);
}
k=0;
dfs1(root,0);
dfs2(root,root);
build(1,1,n);
fer(i,1,m)
{
int opt=read();
if(opt==1)
{
int x=read(),y=read(),z=read();
update(x,y,z);
}
else if(opt==2)
{
int x=read(),y=read();
cout<x,y)<else if(opt==3)
{
int x=read(),y=read();
updateson(x,y);
}
else
{
int x=read();
cout<x)<