zoukankan      html  css  js  c++  java
  • 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();
    
    }
  • 相关阅读:
    prepareSlideshow函数
    moveElement函数与positionMessage函数
    function styleElementSiblings函数与 addClass函数
    stribeTables函数与highlightRows函数
    确定股票见底的六大信号
    调整期六招教你猎杀未来牛股
    王者-甄别同一板块强弱股的方法【真假美猴王】
    王者--分时图五要素教你抓涨停板股票
    王者-【注册制将利好哪些股票】
    王者--看盘口特点猎杀强庄股
  • 原文地址:https://www.cnblogs.com/ling-zhi/p/11808848.html
Copyright © 2011-2022 走看看