树链剖分

  对于树上路径上点权,边权问题,查询次数很多,如果用差分的话,每次查询前都有对c数组求一遍树上前缀和,然后dfs求个dis才能知道两点之间信息,这样的话对于修改然后查询,修改然后查询。。。。这样的复杂度就很高了,于是就要用树链剖分。

数链剖分每次查询和修改的时间复杂度都是(logn)^2,

下面贴几篇写得比较纤细的博客

https://www.cnblogs.com/chinhhh/p/7965433.html     

https://www.luogu.org/problemnew/solution/P3384?page=2

模板题P3384

#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define sjs srand(time(NULL));
#define fuck(x) cout<<#x<<"     "<<x<<endl;
const int maxn=1e5+10;
struct edge
{
    int v,nxt;
    edge(int v=0,int nxt=0){
        this->v=v;
        this->nxt=nxt;
    }
}e[maxn<<1];
int n,m,r,mod,tim,nod[maxn],head[maxn],sz[maxn],son[maxn],fa[maxn],dep[maxn],top[maxn],id[maxn],rk[maxn],sum[maxn<<2],lazy[maxn<<2];//son[i]表示重儿子,top[i]表示 1.i节点连了重链那就是所在重链的顶端节点,2.如果没连的话那就是它本身,id[i]表示i节点的dfs序,rk[i]是映射
void dfs1(int now,int f)
{
    sz[now]=1;
    fa[now]=f;
    dep[now]=dep[f]+1;
    for(int i=head[now];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v==f) continue;
        dfs1(v,now);
        sz[now]+=sz[v];
        if(sz[v]>sz[son[now]])
            son[now]=v;
    }
}
void dfs2(int now,int t){
    top[now]=t;
    id[now]=++tim;
    rk[tim]=now;
    if(!son[now])
        return ;
    dfs2(son[now],t);
    for(int i=head[now];i;i=e[i].nxt)
    {
        int v=e[i].v;
        if(v!=son[now]&&v!=fa[now])
            dfs2(v,v);
    }
}
void pushup(int rt)
{
    sum[rt]=(sum[ls]+sum[rs])%mod;
}
void pushdown(int rt,int L,int R)
{
    if(lazy[rt])
    {
        int mid=(L+R)>>1;
        lazy[ls]+=lazy[rt];
        lazy[ls]%=mod;
        lazy[rs]+=lazy[rt];
        lazy[rs]%=mod;
        sum[ls]+=(mid-L+1)%mod*lazy[rt];
        sum[ls]%=mod;
        sum[rs]+=(R-mid)%mod*lazy[rt];
        sum[rs]%=mod;
        lazy[rt]=0;
    }
}
void build(int rt,int L,int R){
    if(L==R)
    {
        sum[rt]=nod[rk[L]]%mod;
        return ;
    }
    int mid=(L+R)>>1;
    build(ls,L,mid);
    build(rs,mid+1,R);
    pushup(rt);
}
void update(int rt,int L,int R,int l,int r,int k)
{
    if(l<=L&&r>=R)
    {
        lazy[rt]+=k;
        lazy[rt]%=mod;
        sum[rt]+=(R-L+1)%mod*k;
        sum[rt]%=mod;
        return ;
    }
    pushdown(rt,L,R);
    int mid=(L+R)>>1;
    if(r<=mid)
        update(ls,L,mid,l,r,k);
    else
        if(l>=mid+1)
            update(rs,mid+1,R,l,r,k);
        else
        {
            update(ls,L,mid,l,r,k);
            update(rs,mid+1,R,l,r,k);
        }
    pushup(rt);
}
int query(int rt,int L,int R,int l,int r)
{
    if(l<=L&&r>=R)
        return sum[rt];
    pushdown(rt,L,R);
    int mid=(L+R)>>1;
    if(r<=mid)
        return query(ls,L,mid,l,r);
    else
        if(l>=mid+1)
            return query(rs,mid+1,R,l,r);
        else
        {
            int ans=0;
            ans+=query(ls,L,mid,l,r);
            ans%=mod;
            ans+=query(rs,mid+1,R,l,r);
            ans%=mod;
            return ans;
        }
}
void updrange(int x,int y,int k)
{
    int fx=top[x],fy=top[y];
    k%=mod;
    while(fx!=fy){
        if(dep[fx]>=dep[fy]){
            update(1,1,n,id[fx],id[x],k);
            x=fa[fx],fx=top[x];
        }
        else
        {
            update(1,1,n,id[fy],id[y],k);
            y=fa[fy],fy=top[y];
        }
    }
    if(id[x]<=id[y])
        update(1,1,n,id[x],id[y],k);
    else
        update(1,1,n,id[y],id[x],k);
}
int querange(int x,int y){
    int ans=0,fx=top[x],fy=top[y];
    while(fx!=fy){
        if(dep[fx]>=dep[fy]){
            ans+=query(1,1,n,id[fx],id[x]);
            ans%=mod;
            x=fa[fx],fx=top[x];
        }
        else{
            ans+=query(1,1,n,id[fy],id[y]);
            ans%=mod;
            y=fa[fy],fy=top[y];
        }
    }
    if(id[x]<=id[y])
        ans+=query(1,1,n,id[x],id[y]);
    else
        ans+=query(1,1,n,id[y],id[x]);
    ans%=mod;
    return ans;
}
void updsontree(int x,int y)
{
    update(1,1,n,id[x],id[x]+sz[x]-1,y);
}
int quesontree(int x)
{
    return query(1,1,n,id[x],id[x]+sz[x]-1);
}
int main(){
    int cnt=0;
    scanf("%d%d%d%d",&n,&m,&r,&mod);
    for(int i=1;i<=n;i++) scanf("%d",&nod[i]);
    for(int i=1;i<n;i++){
        int u,v;
        scanf("%d%d",&u,&v);
        e[++cnt]=edge(v,head[u]);
        head[u]=cnt;
        e[++cnt]=edge(u,head[v]);
        head[v]=cnt;
    }
    dfs1(r,0);
    dfs2(r,r);
    build(1,1,n);
    while(m--){
        int op,x,y,z;
        scanf("%d",&op);
        if(op==1)
        {
            scanf("%d%d%d",&x,&y,&z);
            updrange(x,y,z);
        }
        else
            if(op==2)
            {
                scanf("%d%d",&x,&y);
                printf("%d
",querange(x,y));
            }
            else
                if(op==3){
                    scanf("%d%d",&x,&y);
                    updsontree(x,y);
                }
                else
                {
                    scanf("%d",&x);
                    printf("%d
",quesontree(x));
                }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/eason9906/p/11754751.html