树上差分备忘

树上差分备忘

点差分

++cnt[u];
++cnt[v];
--cnt[lca(u,v)];
--cnt[fa[lca(u,v)]];

树上主席树就是这个原理来的

边差分

先把边塞给较深的那个点上

++cnt[u];
++cnt[v];
cnt[lca(u,v)]-=2;

统计

一遍\(dfs\),在回溯时加起来即可

void calc(int u, int fa){
    for(int i=head[u];i!=0;i=nxt[i]){
        int v=vv[i];
        if(v==fa) continue;
        calc(v,u);
        ans[u]+=ans[v];
    }
}

板子

[JLOI2014]松鼠的新家

#include <cstdio>
#include <algorithm>
#define MAXN 300003
using namespace std;
int n,a[MAXN];
int head[MAXN],nxt[MAXN*2],vv[MAXN*2],tot;
inline void add_edge(int u, int v){
    vv[++tot]=v;
    nxt[tot]=head[u];
    head[u]=tot;
}
int dep[MAXN],f[MAXN][20];
void dfs(int u, int fa){
    dep[u]=dep[fa]+1;
    f[u][0]=fa;
    for(int i=1;(1<<i)<=dep[u];++i)
        f[u][i]=f[f[u][i-1]][i-1];
    for(int i=head[u];i!=0;i=nxt[i]){
        int v=vv[i];
        if(v==fa) continue;
        dfs(v,u);
    }
}
int get_k(int x){
    int ans=0;
    int t=1;
    while(t<x){
        t*=2;
        ans++;
    }
    return ans;
}
inline int lca(int a, int b){
    if(dep[a]<dep[b]) swap(a,b);
    if(dep[a]!=dep[b]){
        for(int i=get_k(dep[a]);i>=0;--i)
            if(dep[a]-(1<<i)>=dep[b])
                a=f[a][i];
    }
    if(a==b) return a;
    for(int i=get_k(dep[b]);i>=0;i--)
        if(f[a][i]!=f[b][i])
            a=f[a][i],b=f[b][i];
    return f[a][0];
}
int ans[MAXN];
void calc(int u, int fa){
    for(int i=head[u];i!=0;i=nxt[i]){
        int v=vv[i];
        if(v==fa) continue;
        calc(v,u);
        ans[u]+=ans[v];
    }
}
int main()
{
    scanf("%d", &n);
    for(int i=1;i<=n;++i) scanf("%d", &a[i]);
    for(int i=2;i<=n;++i){
        int x,y;scanf("%d %d", &x, &y);
        add_edge(x,y);
        add_edge(y,x);
    }
    dfs(1,0);
    for(int i=1;i<=n-1;++i){
        int s=a[i],t=a[i+1];
        ans[s]++;
        ans[t]++;
        int tmp=lca(s,t);
        ans[tmp]--;
        ans[f[tmp][0]]--;
    }
    calc(1,0);
    for(int i=1;i<=n;++i)
        if(i==a[1]) printf("%d\n", ans[i]);
        else printf("%d\n", ans[i]-1);
    return 0;
}
posted @ 2019-10-28 15:40  Santiego  阅读(130)  评论(0编辑  收藏  举报