关于树链剖分的复杂度分析:首先对于一条轻边(u,v),可由反证法得出size(v)<size(u)/2。所以对于任意点,从根到这个点的路径上,轻边数量少于log(n)条(否则这棵树不止n个点)。相连的重边可以当成一根重链一起跳,从根到某点的路劲上,断开的重链必定不超过log(n)条,因为断开的重链之间必定由轻边链接,而轻边数量不超过log(n)。所以每次关于两点路径的查询/修改在树上的复杂度为log(n)级别,再乘上每次操作时数据结构(线段树/树状数组)的log(n),每次操作的实际复杂度为log(n)^2。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define root 1,1,n
#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
using namespace std;
const int N=1e5+4;
int n,m,O,P;
int head[N],etot;
struct Edge {
int v,nxt;
}e[N<<1];
int siz[N],son[N],dep[N],fa[N];
int in[N],out[N],top[N],rk[N],tim;
int a[N],laz[N<<2],sum[N<<2];
inline int read() {
int x=0,f=1;char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
while (c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
return x*f;
}
inline void adde(int u,int v) {
e[++etot].nxt=head[u],e[etot].v=v,head[u]=etot;
}
inline void dfs1(int p,int f) {
int mx=0;
dep[p]=dep[fa[p]=f]+1,siz[p]=1;
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (v^f) {
dfs1(v,p);
siz[p]+=siz[v];
if (mx<siz[v]) {
mx=siz[v];
son[p]=v;
}
}
}
}
inline void dfs2(int p,int tp) {
rk[in[p]=++tim]=p,top[p]=tp;
if (~son[p]) dfs2(son[p],tp);
for (int i=head[p];~i;i=e[i].nxt) {
int v=e[i].v;
if (v^son[p]&&v^fa[p]) dfs2(v,v);
}
out[p]=tim;
}
inline void pushup(int rt) {
sum[rt]=(sum[rt<<1]+sum[rt<<1|1])%P;
}
inline void pushdown(int rt,int len) {
if (laz[rt]) {
(laz[rt<<1]+=laz[rt])%=P;
(laz[rt<<1|1]+=laz[rt])%=P;
(sum[rt<<1]+=(len-(len>>1))*laz[rt])%=P;
(sum[rt<<1|1]+=(len>>1)*laz[rt])%=P;
laz[rt]=0;
}
}
inline void build(int rt,int l,int r) {
if (l==r) {
sum[rt]=a[rk[l]];
return ;
}
int mid=l+r>>1;
build(lson);
build(rson);
pushup(rt);
}
inline void modify(int rt,int l,int r,int L,int R,int val) {
if (L<=l&&r<=R) {
(sum[rt]+=(r-l+1)*val)%=P;
(laz[rt]+=val)%=P;
return ;
}
pushdown(rt,r-l+1);
int mid=l+r>>1;
if (L<=mid) modify(lson,L,R,val);
if (mid<R) modify(rson,L,R,val);
pushup(rt);
}
inline int query(int rt,int l,int r,int L,int R) {
if (L<=l&&r<=R) return sum[rt];
pushdown(rt,r-l+1);
int mid=l+r>>1,ret=0;
if (L<=mid) (ret+=query(lson,L,R))%=P;
if (mid<R) (ret+=query(rson,L,R))%=P;
return ret;
}
inline void add(int x,int y,int val) {
int tx=top[x],ty=top[y];
while (tx^ty) {
if (dep[tx]<dep[ty]) {
x^=y^=x^=y;
tx^=ty^=tx^=ty;
}
modify(root,in[tx],in[x],val);
x=fa[tx],tx=top[x];
}
if (dep[x]<dep[y]) x^=y^=x^=y;
modify(root,in[y],in[x],val);
}
inline int ask(int x,int y) {
int tx=top[x],ty=top[y],ret=0;
while (tx^ty) {
if (dep[tx]<dep[ty]) {
x^=y^=x^=y;
tx^=ty^=tx^=ty;
}
(ret+=query(root,in[tx],in[x]))%=P;
x=fa[tx],tx=top[x];
}
if (dep[x]<dep[y]) x^=y^=x^=y;
(ret+=query(root,in[y],in[x]))%=P;
return ret;
}
int main() {
// freopen("in1.txt","r",stdin);
memset(head,-1,sizeof(head));
memset(son,-1,sizeof(son));
n=read(),m=read(),O=read(),P=read();
for (register int i=1;i<=n;++i) a[i]=read()%P;
for (register int i=1;i<n;++i) {
int u=read(),v=read();
adde(u,v);
adde(v,u);
}
dfs1(O,0);
dfs2(O,O);
build(root);
for (register int i=0;i<m;++i) {
int opt=read();
switch (opt) {
case 1: {
int x=read(),y=read(),z=read();
add(x,y,z);
break;
}
case 2: {
int x=read(),y=read();
printf("%d\n",ask(x,y));
break;
}
case 3: {
int x=read(),z=read();
modify(root,in[x],out[x],z);
break;
}
case 4: {
int x=read();
printf("%d\n",query(root,in[x],out[x]));
break;
}
}
}
return 0;
}