树链剖分模板

树链剖分:

通过两次dfs,分别对每个节点为根节点的树的节点个数,重点,父亲节点,深度与重链头结点,在线段树上对应的id,每个id对应的原本序列rk,进行初始化。

这样就完成了树链剖分。剩下的就是在在剖分过得树上进行求和,更新操作。

洛谷p3384

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
const int M=1e5+100;
int f[M];
int d[M];
int siz[M];
int rk[M];//保存树链剖分后,节点编号对应树上位置
int id[M];//节点剖分后所对应的编号,id[rk[x]]]=x;
int top[M];
int son[M];
int n,m,r,q;
int tr[M*4],lazy[M*4],cnt,a[M];
vector<int>v[M];
void dfs1(int rt,int now,int dep)
{
    siz[now]=1;
    f[now]=rt;
    d[now]=dep;
    for(int i=0;i<v[now].size();i++)
    {
        if(v[now][i]!=rt)
        {
            dfs1(now,v[now][i],dep+1);
             siz[now]+=siz[v[now][i]];
        if(siz[v[now][i]]>siz[son[now]])
            son[now]=v[now][i];
        }
    }
}
void dfs2(int now,int t)
{
    top[now]=t;
    id[now]=++cnt;
    rk[cnt]=now;
    if(!son[now])
    {
        return;
    }
    dfs2(son[now],t);//将重链链接在一起
    for(int i=0;i<v[now].size();i++)
    {
        if(v[now][i]!=son[now]&&v[now][i]!=f[now])
        {
            dfs2(v[now][i],v[now][i]);
        }
    }

}
void pushup(int i)
{
    tr[i]=tr[i*2]+tr[i*2+1];
    tr[i]%=q;
}
void pushdown(int i,int l,int r)
{
    int mid=(l+r)/2;
    lazy[i<<1]=(lazy[i<<1]+lazy[i])%q;
    lazy[i<<1|1]=(lazy[i<<1|1]+lazy[i])%q;
    tr[i<<1]=(tr[i<<1]+lazy[i]*(mid-l+1))%q;
    tr[i<<1|1]=(tr[i<<1|1]+lazy[i]*(r-mid))%q;
    lazy[i]=0;
}
void build(int i,int l,int r)
{
    if(l==r)
    {
        lazy[i]=0;
        tr[i]=a[rk[l]]%q;
        return ;
    }
    lazy[i]=0;
    int mid=(l+r)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    pushup(i);
}
void update(int i,int l,int r,int x,int y,int t)
{
    if(x<=l&&y>=r)
    {
        tr[i]=(tr[i]+(r-l+1)*t)%q;
        lazy[i]=(lazy[i]+t)%q;
        return;
    }
     if(lazy[i]!=0)
        pushdown(i,l,r);
    int mid=(l+r)/2;
    if(x<=mid)
    {
        update(i*2,l,mid,x,y,t);
    }
    if(y>mid)
    {
        update(i*2+1,mid+1,r,x,y,t);
    }
    pushup(i);
}
int query(int i,int l,int r,int x,int y)
{
    if(x<=l&&y>=r)
    {
        return tr[i];
    }
    if(lazy[i]!=0)
        pushdown(i,l,r);
    int ans=0;
    int mid=(l+r)/2;
    if(x<=mid)
        ans+=query(i*2,l,mid,x,y);
    if(y>mid)
        ans+=query(i*2+1,mid+1,r,x,y);
        ans%=q;
    return ans;
}
int ask(int x,int y)
{
    int ans=0;
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
        ans=(ans+query(1,1,n,id[fx],id[x]))%q;
        x=f[top[x]];
        fx=top[x];
    }
    if(d[x]>d[y])
        swap(x,y);
    ans=(ans+query(1,1,n,id[x],id[y]))%q;
    return ans;
}
void qupdate(int x,int y,int t)
{
    t%=q;
    int fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
        update(1,1,n,id[fx],id[x],t);
        x=f[top[x]];
        fx=top[x];
    }
    if(d[x]>d[y])
        swap(x,y);
    update(1,1,n,id[x],id[y],t);
}
int main()
{
    cnt=0;
    scanf("%d%d%d%d",&n,&m,&r,&q);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=0;i<n-1;i++)
    {
        int x,y;
        scanf("%d%d",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs1(0,r,1);
    dfs2(r,r);
    build(1,1,n);
    while(m--)
    {
        int op;
        int x,y,z;
        scanf("%d",&op);
        switch (op)
        {
        case 1:
            scanf("%d%d%d",&x,&y,&z);
            qupdate(x,y,z);
            break;
        case 2:
            scanf("%d%d",&x,&y);
            printf("%d\n",ask(x,y));
            break;
        case 3:
            scanf("%d%d",&x,&z);
            update(1,1,n,id[x],id[x]+siz[x]-1,z);
            break;
        case 4:
            scanf("%d",&x);
            printf("%d\n",query(1,1,n,id[x],id[x]+siz[x]-1)%q);
            break;
        }
    }
    return 0;
}

洛谷p3178

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <vector>
using namespace std;
const int M=1e5+100;
long long f[M];
long long d[M];
long long siz[M];
long long rk[M];//保存树链剖分后,节点编号对应树上位置
long long id[M];//节点剖分后所对应的编号,id[rk[x]]]=x;
long long top[M];
long long son[M];
long long n,m;
long long tr[M*4],lazy[M*4],cnt,a[M];
vector<long long>v[M];
void dfs1(long long rt,long long now,long long dep)
{
    siz[now]=1;
    f[now]=rt;
    d[now]=dep;
    for(long long i=0;i<v[now].size();i++)
    {
        if(v[now][i]!=rt)
        {
            dfs1(now,v[now][i],dep+1);
             siz[now]+=siz[v[now][i]];
        if(siz[v[now][i]]>siz[son[now]])
            son[now]=v[now][i];
        }
    }
}
void dfs2(long long now,long long t)
{
    top[now]=t;
    id[now]=++cnt;
    rk[cnt]=now;
    if(!son[now])
    {
        return;
    }
    dfs2(son[now],t);//将重链链接在一起
    for(long long i=0;i<v[now].size();i++)
    {
        if(v[now][i]!=son[now]&&v[now][i]!=f[now])
        {
            dfs2(v[now][i],v[now][i]);
        }
    }

}
void pushup(long long i)
{
    tr[i]=tr[i*2]+tr[i*2+1];
}
void pushdown(long long i,long long l,long long r)
{
    long long mid=(l+r)/2;
    lazy[i<<1]=(lazy[i<<1]+lazy[i]);
    lazy[i<<1|1]=(lazy[i<<1|1]+lazy[i]);
    tr[i<<1]=(tr[i<<1]+lazy[i]*(mid-l+1));
    tr[i<<1|1]=(tr[i<<1|1]+lazy[i]*(r-mid));
    lazy[i]=0;
}
void build(long long i,long long l,long long r)
{
    if(l==r)
    {
        lazy[i]=0;
        tr[i]=a[rk[l]];
        return ;
    }
    lazy[i]=0;
    long long mid=(l+r)/2;
    build(i*2,l,mid);
    build(i*2+1,mid+1,r);
    pushup(i);
}
void update(long long i,long long l,long long r,long long x,long long y,long long t)
{
    if(x<=l&&y>=r)
    {
        tr[i]=(tr[i]+(r-l+1)*t);
        lazy[i]=(lazy[i]+t);
        return;
    }
     if(lazy[i]!=0)
        pushdown(i,l,r);
    long long mid=(l+r)/2;
    if(x<=mid)
    {
        update(i*2,l,mid,x,y,t);
    }
    if(y>mid)
    {
        update(i*2+1,mid+1,r,x,y,t);
    }
    pushup(i);
}
long long query(long long i,long long l,long long r,long long x,long long y)
{
    if(x<=l&&y>=r)
    {
        return tr[i];
    }
    if(lazy[i]!=0)
        pushdown(i,l,r);
    long long ans=0;
    long long mid=(l+r)/2;
    if(x<=mid)
        ans+=query(i*2,l,mid,x,y);
    if(y>mid)
        ans+=query(i*2+1,mid+1,r,x,y);
    return ans;
}
long long ask(long long x,long long y)
{
    long long ans=0;
    long long fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
        ans=(ans+query(1,1,n,id[fx],id[x]));
        x=f[top[x]];
        fx=top[x];
    }
    if(d[x]>d[y])
        swap(x,y);
    ans=(ans+query(1,1,n,id[x],id[y]));
    return ans;
}
void qupdate(long long x,long long y,long long t)
{
    long long fx=top[x],fy=top[y];
    while(fx!=fy)
    {
        if(d[fx]<d[fy])swap(x,y),swap(fx,fy);
        update(1,1,n,id[fx],id[x],t);
        x=f[top[x]];
        fx=top[x];
    }
    if(d[x]>d[y])
        swap(x,y);
    update(1,1,n,id[x],id[y],t);
}
int main()
{
    cnt=0;
    scanf("%lld%lld",&n,&m);
    for(long long i=1;i<=n;i++)
        scanf("%lld",&a[i]);
    for(long long i=0;i<n-1;i++)
    {
        long long x,y;
        scanf("%lld%lld",&x,&y);
        v[x].push_back(y);
        v[y].push_back(x);
    }
    dfs1(0,1,1);
    dfs2(1,1);
    build(1,1,n);
    while(m--)
    {
        long long op;
        int x,y;
        scanf("%lld",&op);
        switch (op)
        {
        case 1:
            scanf("%d%d",&x,&y);
            update(1,1,n,id[x],id[x],y);
            break;
        case 2:
            scanf("%d%d",&x,&y);
            update(1,1,n,id[x],id[x]+siz[x]-1,y);
            break;
        case 3:
            scanf("%d",&x);
            printf("%lld\n",ask(1,x));
            break;
        }
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值