luogu_P3384 【模板】树链剖分
树链剖分,差不多就是树上分块
核心思想:利用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(); }