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();

}

猜你喜欢

转载自www.cnblogs.com/ling-zhi/p/11808848.html