树上差分

树上差分

定义

树上差分就是树上的差分——gzy

用途(差分)

它可以维护多次对序列的一个区间加上一个数,并在最后询问某一位的数或是多次询问某一位的数。(总之修改操作一定要在查询操作之前)

点差分

对于树上的区间(假设为 [l,r][l,r]),我们可以把它看成从 ll走到 rr的简单路径

前缀和就可以看成是每个点的子树和(包括该点)

核心代码:

    for(int i=1;i<=k;i++){
        int a,c;
        cin>>a>>c;
        int lc=lca(a,c);//计算出a,c的最近公共祖先,以便处理a,c的简单路径
        b[a]++;
                b[f[lc][0]]--;//消除a带来的影响
        b[c]++;
        b[lc]--;//lc这个点实际上会因为a,c加两次,而实际上他只需要加一次,所以减掉一次
    }

求前缀和:

void dfs(int x,int fa){
    //cout<<x<<endl;
    for(int i=head[x];i;i=nex[i]){
        int y=ver[i];
        if(y==fa) continue;
        dfs(y,x);
        b[x]+=b[y];//所有子树的和
    }
    return ;
}

边差分

将边的差分存在点中(子节点,因为具有唯一性)

需要注意的是,修改的方法和点差分有些许不同

代码解释:

 

for(int i=1;i<=m;i++){
        int a,c;
        cin>>a>>c;
        int lc=lca(a,c);
        b[a]++;
        b[c]++;
        b[lc]-=2;//这里b[lc]就要减两次了,因为b[lc]这条边并不在我们期望的路径中,b[f[lc][0]]就更不用管了
    }

 

来一道例题:https://www.luogu.com.cn/problem/P3128

AC代码:

#include<bits/stdc++.h>
#include<queue>
using namespace std;
const int N=3e5;
int n,k;
int ord[N];
int ver[2*N],head[N],nex[2*N];
int d[N], f[N][25];
int b[N];
int idx=1;
queue<int>q;
int t;

void add(int x,int y){
    ver[++idx]=y;
    nex[idx]=head[x];
    head[x]=idx;
}

void bfs(){
    q.push(1);
    d[1]=1;
    while(!q.empty()){
        int x=q.front();
        q.pop();
        for(int i=head[x];i;i=nex[i]){
            int y=ver[i];
            if(d[y]) continue;
            d[y]=d[x]+1;
            f[y][0]=x;
            for(int j=1;j<=t;j++){
                f[y][j]=f[f[y][j-1]][j-1];
            }
            q.push(y);
        }
    }
    return ;
}

void dfs(int x,int fa){
    //cout<<x<<endl;
    for(int i=head[x];i;i=nex[i]){
        int y=ver[i];
        if(y==fa) continue;
        dfs(y,x);
        b[x]+=b[y];
    }
    return ;
}

int lca(int x,int y){
    if(d[x]<d[y]) swap(x,y);
    for(int i=t;i>=0;i--){
        if(d[f[x][i]]>=d[y]) x=f[x][i];
    }
    if(x==y) return x;
    for(int i=t;i>=0;i--){
        if(f[x][i]!=f[y][i]){
            x=f[x][i];
            y=f[y][i];
        }
    }
    return f[x][0];
}

int main(){
    cin>>n>>k;
    t=(int)(log(n)/log(2))+1;
    for(int i=1;i<n;i++){
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
    }
    bfs();
    for(int i=1;i<=k;i++){
        int a,c;
        cin>>a>>c;
        int lc=lca(a,c);
        b[a]++;
        b[c]++;
        b[lc]--;
        b[f[lc][0]]--;
    }
    
    dfs(1,0);
    int maxn=-1;
    for(int i=1;i<=n;i++){
        maxn=max(maxn,b[i]);
    }
    cout<<maxn;
    return 0;
}

 

posted @ 2021-02-03 17:30  爆零王  阅读(163)  评论(0编辑  收藏  举报