树链剖分-重链剖分模板

#include <iostream>
#include <vector>
using namespace std;
const int maxn=(int)1e5+5;

int n,q;
vector<int>G[maxn];

/*---树链剖分---*/
int fa[maxn],son[maxn],sz[maxn],deep[maxn];
void dfs1(int p,int u,int d){
    deep[u]=d;fa[u]=p;sz[u]=1;
    for(auto v:G[u]){
        if(v==fa[u])continue;
        dfs1(u,v,d+1);
        sz[u]+=sz[v];
        if(sz[v]>sz[son[u]])son[u]=v;
    }
}

int id[maxn],mark[maxn],top[maxn],cnt;
void dfs2(int t,int u){
    id[u]=++cnt;mark[cnt]=u;
    top[u]=t;
    if(son[u])dfs2(t,son[u]);
    for(auto v:G[u]){
        if(v==fa[u])continue;
        if(v==son[u])continue;
        dfs2(v,v);
    }
}
/*---树链剖分---*/

/*---线段树---*/
#define lson rt<<1
#define rson rt<<1|1
int sum[maxn<<2],lazy[maxn<<2];

//如果需要建树
void build(){}

void pushdown(int rt,int l,int r){
    if(lazy[rt]){
        lazy[lson]+=lazy[rt];
        lazy[rson]+=lazy[rt];
        sum[lson]+=lazy[rt]*l;
        sum[rson]+=lazy[rt]*r;
        lazy[rt]=0;
    }
}

void pushup(int rt){
    sum[rt]=sum[lson]+sum[rson];
}

void update(int rt,int x,int l,int r,int L,int R){
    if(l<=L && r>=R){
        lazy[rt]+=x;
        sum[rt]+=(R-L+1)*x;
        return;
    }
    int mid=(L+R)>>1;
    pushdown(rt,mid-L+1,R-mid);
    if(r<=mid)update(lson,x,l,r,L,mid);
    else if(l>mid)update(rson,x,l,r,mid+1,R);
    else update(lson,x,l,mid,L,mid),update(rson,x,mid+1,r,mid+1,R);
    pushup(rt);
};

int query(int rt,int l,int r,int L,int R){
    if(l<=L && r>=R) return sum[rt];
    int mid=(L+R)>>1;
    pushdown(rt,mid-L+1,R-mid);
    if(r<=mid) return query(lson,l,r,L,mid);
    else if(l>mid) return query(rson,l,r,mid+1,R);
    else return query(lson,l,mid,L,mid)+query(rson,mid+1,r,mid+1,R);
}

/*---线段树---*/

/*---树链+线段树---*/

void change(int a,int b,int x){
    while(top[a]!=top[b]){
        //使 b 的 top 的深度大
        if(deep[top[a]]>deep[top[b]])swap(a,b);
        int tb=top[b];
        int s=id[tb],e=id[b];
        update(1,x,s,e,1,n);
        b=fa[tb];
    }

    if(id[a]>id[b])swap(a,b);
    update(1,x,id[a],id[b],1,n);
}

int ask(int a,int b){
    int ans=0;
    while(top[a]!=top[b]){
        if(deep[top[a]]>deep[top[b]])swap(a,b);
        int tb=top[b];
        int s=id[tb],e=id[b];
        ans+=query(1,s,e,1,n);
        b=fa[tb];
    }

    if(id[a]>id[b])swap(a,b);
    ans+=query(1,id[a],id[b],1,n);
    return ans;
}

/*---树链+线段树---*/

int main(){
    ios::sync_with_stdio(false);
    cin>>n>>q;
    for(int i=1,u,v;i<n;i++){
        cin>>u>>v;
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs1(0,1,1);
    dfs2(1,1);
    while(q--){
        int a,b,c,d;
        cin>>a>>b>>c>>d;
        change(a,b,1);
        cout<<ask(c,d)<<endl;
        change(a,b,-1);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值