zoukankan      html  css  js  c++  java
  • 树剖模板(洛谷P3384 【模板】树链剖分)(树链剖分,树状数组,树的dfn序)

    洛谷题目传送门

    仍然是一个板子。

    不过蒟蒻去学了一下BIT维护区间修改区间求和,常数果真十分优秀

    设数列为(a_i),差分数组(d_ i=a_ i-a_ {i-1}),前缀和(s_i=sumlimits_ {j=1}^ia_ j)

    显然有(a_ i=sumlimits_ {j=1}^id_ j)

    于是大力展开得到

    [s_i=sumlimits_{j=1}^i(i-j+1)d_j ]

    [s_i=(i+1)sumlimits_{i=1}^jd_j-sumlimits_{j=1}^ijd_j ]

    用BIT维护(d_i)(id_i)的前缀和即可。

    #include<cstdio>
    #define RG register
    #define R RG int
    #define G          if(++ip==ie)fread (ip=ibuf,1,L,stdin)
    #define P(C) *op=C;if(++op==oe)fwrite(op=obuf,1,L,stdout)
    typedef long long LL;
    const int N=1e5+9,M=N<<1,L=1<<19;
    char ibuf[L],*ie=ibuf+L,*ip=ie-1,obuf[L],*oe=obuf+L,*op=obuf;
    int YL,n,p,a[N],he[N],ne[M],to[M],f[N],s[N],id[N],pr[N],dep[N],top[N],d[N],e[N];
    inline int in(){
        G;while(*ip<'-')G;
        R x=*ip&15;G;
        while(*ip>'-'){(x*=10)+=*ip&15;G;}
        return x;
    }
    void out(R x){
        if(x>9)out(x/10);
        P(x%10|'0');
    }
    inline void swap(R&x,R&y){
        R z=x;x=y;y=z;
    }
    void dfs1(R x,R y){
        s[x]=1;
        dep[x]=dep[f[x]=y]+1;
        for(R i=he[x];i;i=ne[i])
            if(to[i]!=y)dfs1(to[i],x);
        s[y]+=s[x];
        if(s[pr[y]]<s[x])pr[y]=x;
    }
    void dfs2(R x,R y){
        top[x]=y;
        d[id[x]=++p]=a[x];
        if(!pr[x])return;
        dfs2(pr[x],y);
        for(R i=he[x];i;i=ne[i])
            if(!id[to[i]])dfs2(to[i],to[i]);
    }
    inline void mdf(R*d,R i,R v){
        for(;i<=n;i+=i&-i)(d[i]+=v)%=YL;
    }
    inline void upd(R l,R r,R v){
        mdf(d,l,v);mdf(e,l,(LL)v*l%YL);v=YL-v;
        mdf(d,r,v);mdf(e,r,(LL)v*r%YL);
    }
    inline int qry(R*d,R i){
        R v=0;
        for(;i;i-=i&-i)(v+=d[i])%=YL;
        return v;
    }
    inline int ask(R l,R r){
        return (((LL)(r+1)*qry(d,r)-qry(e,r)-(LL)(l+1)*qry(d,l)+qry(e,l))%YL+YL)%YL;
    }
    int main(){
        n=in();R m=in(),rt=in(),i,x,y,z,ans;YL=in();
        for(i=1;i<=n;++i)a[i]=in();
        for(i=1;i<n;++i){
            x=in();y=in();
            ne[++p]=he[x];to[he[x]=p]=y;
            ne[++p]=he[y];to[he[y]=p]=x;
        }
        p=0;dfs1(rt,0);dfs2(rt,rt);
        for(i=n;i;--i){
            d[i]=((d[i]-d[i-1])%YL+YL)%YL;
            e[i]=(LL)i*d[i]%YL;
        }
        for(i=1;i<=n;++i){
            if((x=i+(i&-i))>n)continue;
            (d[x]+=d[i])%=YL;(e[x]+=e[i])%=YL;
        }
        while(m--)
            switch(in()){
                case 1:x=in();y=in();z=in()%YL;
                    for(;top[x]!=top[y];x=f[top[x]]){
                        if(dep[top[x]]<dep[top[y]])swap(x,y);
                        upd(id[top[x]],id[x]+1,z);
                    }
                    if(dep[x]<dep[y])swap(x,y);
                    upd(id[y],id[x]+1,z);
                    break;
                case 2:x=in();y=in();ans=0;
                    for(;top[x]!=top[y];x=f[top[x]]){
                        if(dep[top[x]]<dep[top[y]])swap(x,y);
                        ans+=ask(id[top[x]]-1,id[x]);
                    }
                    if(dep[x]<dep[y])swap(x,y);
                    out((ans+ask(id[y]-1,id[x]))%YL);P('
    ');
                    break;
                case 3:x=in();z=in()%YL;
                    upd(id[x],id[x]+s[x],z);
                    break;
                case 4:x=in();
                    out(ask(id[x]-1,id[x]+s[x]-1));P('
    ');
            }
        fwrite(obuf,1,op-obuf,stdout);
        return 0;
    }
    
  • 相关阅读:
    C# 字典 Dictionary 转 JSON 格式遍历
    jquery-easyui-tree异步树
    android 开发环境搭建
    解决android sdk 无法更新
    043——VUE中组件之使用.sync修饰符与computed计算属性实现购物车原理
    laravel中数据库迁移的使用:
    002PHP文件处理——文件处理 is_dir mkdir getcwd chdir rmdir
    001PHP文件处理——文件处理disk_total_space disk_free_space basename dirname file_exists filetype
    042——VUE中组件之子组件使用$on与$emit事件触发父组件实现购物车功能
    041——VUE中组件之pros数据的多种验证机制实例详解
  • 原文地址:https://www.cnblogs.com/flashhu/p/9463786.html
Copyright © 2011-2022 走看看