树链剖分,差不多就是树上分块
核心思想:利用dfs序的连续性,把链和子树套在线段树上做
代码略长,记得随时取模
#include<iostream>
#include<cstdio>
#define ri register int
#define u int
namespace opt {
inline u in() {
u x(0),f(1);
char s(getchar());
while(s<'0'||s>'9') {
if(s=='-') f=-1;
s=getchar();
}
while(s>='0'&&s<='9') {
x=(x<<1)+(x<<3)+s-'0';
s=getchar();
}
return x*f;
}
}
using opt::in;
#define NN 500005
#define MM 500005
namespace tu {
u N,M,R,P;//
u v[NN];//原点权值
u w[NN];//dfsz序权值
u num;//num,dfs序
u cnt,h[NN];//星
u to[NN];//原点->dfs序
struct node {
u to,next;
} a[MM<<1]; //星
struct nods {
u siz,fa,dep,son,top;//大小,父亲,深度,重儿子 ,链顶
} poi[NN]; //原点信息
}
using tu::P;
namespace xds {
struct node {
u sum,add,l,r;
} a[NN<<2];
void build(const u &rt,const u &l,const u &r) {
a[rt].l=l,a[rt].r=r;
if(l^r) {
u mid(l+r>>1),_x(rt<<1),_y(rt<<1|1);
build(_x,l,mid),build(_y,mid+1,r);
a[rt].sum=(a[_x].sum+a[_y].sum)%P;
} else {
a[rt].sum=tu::w[l];
return;
}
}
void pushdown(const u &rt) {
if(a[rt].add) {
u _x(rt<<1),_y(rt<<1|1);
a[_x].add=(a[_x].add+a[rt].add)%P;
a[_y].add=(a[_y].add+a[rt].add)%P;
a[_x].sum=(a[_x].sum+(a[_x].r-a[_x].l+1)*a[rt].add)%P;
a[_y].sum=(a[_y].sum+(a[_y].r-a[_y].l+1)*a[rt].add)%P;
a[rt].add=0;
}
}
u query(const u &rt,const u &l,const u &r) {
if(a[rt].l>=l&&a[rt].r<=r) return a[rt].sum;
pushdown(rt);
u _x(rt<<1),_y(rt<<1|1),_re(0);
if(a[_x].r>=l) _re=(_re+query(_x,l,r))%P;
if(a[_y].l<=r) _re=(_re+query(_y,l,r))%P;
return _re;
}
void update(const u &rt,const u &l,const u &r,const u &x) {
if(a[rt].l>=l&&a[rt].r<=r) {
a[rt].add=(a[rt].add+x)%P;
a[rt].sum=(a[rt].sum+(a[rt].r-a[rt].l+1)*x)%P;
return;
}
pushdown(rt);
u _x(rt<<1),_y(rt<<1|1);
if(a[_x].r>=l) update(_x,l,r,x);
if(a[_y].l<=r) update(_y,l,r,x);
a[rt].sum=(a[_x].sum+a[_y].sum)%P;
}
}
namespace pao_fi {
using tu::poi;
void dfs1(const u &x,const u &prt,const u &deep) {
poi[x].dep=deep,poi[x].siz=1,poi[x].fa=prt;
u mx(0);
for(ri i(tu::h[x]); i; i=tu::a[i].next) {
u _y(tu::a[i].to);
if(_y^prt) {
dfs1(_y,x,deep+1);
poi[x].siz+=poi[_y].siz;
if(poi[_y].siz>mx) mx=poi[_y].siz,poi[x].son=_y;
}
}
}
using tu::num;
void dfs2(const u &x,const u &prt,const u &top) {
tu::to[x]=++num,tu::w[num]=tu::v[x],poi[x].top=top;
if(!poi[x].son) return;
dfs2(poi[x].son,x,top);
for(ri i(tu::h[x]); i; i=tu::a[i].next) {
u _y(tu::a[i].to);
if((_y^prt)&&(_y^poi[x].son)) {
dfs2(_y,x,_y);
}
}
}
void chg_l(u x,u y,const u &v){
while(poi[x].top^poi[y].top){
if(poi[poi[x].top].dep<poi[poi[y].top].dep) std::swap(x,y);
xds::update(1,tu::to[poi[x].top],tu::to[x],v);
x=poi[poi[x].top].fa;
}
if(poi[x].dep>poi[y].dep) std::swap(x,y);
xds::update(1,tu::to[x],tu::to[y],v);
}
void chg_s(const u &x,const u &v){
xds::update(1,tu::to[x],tu::to[x]+poi[x].siz-1,v);
}
u qry_l(u x,u y){
u _re(0);
while(poi[x].top^poi[y].top){
if(poi[poi[x].top].dep<poi[poi[y].top].dep) std::swap(x,y);
_re=(_re+xds::query(1,tu::to[poi[x].top],tu::to[x]))%P;
x=poi[poi[x].top].fa;
}
if(poi[x].dep>poi[y].dep) std::swap(x,y);
_re=(_re+xds::query(1,tu::to[x],tu::to[y]))%P;
return _re;
}
u qry_s(const u &x){
return xds::query(1,tu::to[x],tu::to[x]+poi[x].siz-1);
}
}
namespace mainstay {
using namespace tu;
inline void add(const u &x,const u &y) {
a[++cnt].to=y,a[cnt].next=h[x],h[x]=cnt;
}
inline void solve() {
N=in(),M=in(),R=in(),P=in();
for(ri i(1); i<=N; ++i) v[i]=in()%P;
for(ri i(1); i<N; ++i) {
u _a(in()),_b(in());
add(_a,_b),add(_b,_a);
}
pao_fi::dfs1(R,0,1),pao_fi::dfs2(R,0,R),xds::build(1,1,N);
for(ri i(1); i<=M; ++i) {
u _k(in());
if(_k==1) {
u _a(in()),_b(in()),_c(in()%P);
pao_fi::chg_l(_a,_b,_c);
}
if(_k==3) {
u _a(in()),_c(in()%P);
pao_fi::chg_s(_a,_c);
}
if(_k==2) {
u _a(in()),_b(in());
std::cout<<pao_fi::qry_l(_a,_b)<<std::endl;
}
if(_k==4) {
u _a(in());
std::cout<<pao_fi::qry_s(_a)<<std::endl;
}
}
}
}
int main() {
//freopen("x.txt","r",stdin);
std::ios::sync_with_stdio(false);
mainstay::solve();
}