zoukankan      html  css  js  c++  java
  • 树上差分备忘

    树上差分备忘

    点差分

    ++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
    ", ans[i]);
            else printf("%d
    ", ans[i]-1);
        return 0;
    }
    
  • 相关阅读:
    java爬虫(jsoup)
    python之模块分类(六)
    Python之模块分类(五)
    python之模块分类(四)
    python之模块分类(三)
    Linux系统引导过程
    python之模块分类(二)
    linux 进程管理
    python之模块分类(一)
    python基础之模块导入
  • 原文地址:https://www.cnblogs.com/santiego/p/11752718.html
Copyright © 2011-2022 走看看