zoukankan      html  css  js  c++  java
  • bzoj 3631 (树上差分)

    传送门

    题意:

    给你一棵有nn个结点的树,现在给你一个大小为nn的排列,说明你的行走路径。你每经过树上的每一个点,你就需要将这个点的点权加1。问你最后所有点的点权大小。

    题目分析:

    根据题目的意思,很明显这道题是一个非常典型的点差分的问题。我们只需要对结点uiu_iviv_i以及lca(ui,vi)lca(u_i,v_i)fa[lca(ui,vi)]fa[lca(u_i,v_i)]进行差分之后即可。

    最后我们还需要注意的是,上述的差分过程中,会对那些既属于起点,又属于终点的点会被重复经过一次。因此我们只需要在最后把他们1-1即可。

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=600005;
    const int LOG=20;
    struct Node{
        int to,next;
    }q[maxn<<1];
    int head[maxn],cnt=0;
    void add_edge(int from,int to){
        q[cnt].to=to;
        q[cnt].next=head[from];
        head[from]=cnt++;
    }
    struct LCA{//倍增lca
        int anc[maxn][LOG],depth[maxn];
        void dfs(int x,int fa,int dis){
            anc[x][0]=fa;depth[x]=dis;
            for(int i=head[x];i!=-1;i=q[i].next){
                int to=q[i].to;
                if(to==fa) continue;
                dfs(to,x,dis+1);
            }
        }
        void init(int root,int n){
            dfs(root,-1,1);
            for(int j=1;j<LOG;j++){
                for(int i=1;i<=n;i++){
                    anc[i][j]=anc[ anc[i][j-1] ][j-1];
                }
            }
        }
        void swim(int &x,int h){
            for(int i=0;h>0;i++){
                if(h&1)
                    x=anc[x][i];
                h>>=1;
            }
        }
        int query(int x,int y){
            if(depth[x]<depth[y]) swap(x,y);
            swim(x,depth[x]-depth[y]);
            if(x==y) return x;
            for(int i=LOG-1;i>=0;i--){
                if(anc[x][i]!=anc[y][i]){
                    x=anc[x][i];
                    y=anc[y][i];
                }
            }
            return anc[x][0];
        }
    }lca;
    int Bit[maxn];
    int a[maxn];
    void Search(int x,int fa){//最优一次dfs获取权值
        for(int i=head[x];i!=-1;i=q[i].next){
            int to=q[i].to;
            if(to==fa) continue;
            Search(to,x);
            Bit[x]+=Bit[to];
        }
    }
    int main()
    {
        int n,m;
        scanf("%d",&n);
        memset(head,-1,sizeof(head));
        cnt=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<n;i++){
            int from,to;
            scanf("%d%d",&from,&to);
            add_edge(from,to);
            add_edge(to,from);
        }
        lca.init(1,n);
        for(int i=2;i<=n;i++){
            Bit[a[i-1]]++;
            Bit[a[i]]++;
            int x=lca.query(a[i-1],a[i]);
            Bit[x]--;
            Bit[lca.anc[x][0]]--;
        }
        Search(1,-1);
        for(int i=2;i<=n;i++){
            Bit[a[i]]--;
        }
        for(int i=1;i<=n;i++){
            printf("%d
    ",Bit[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    Andrew Ng机器学习课程12
    Andrew Ng机器学习课程12
    排序算法十一:计数排序
    排序算法十一:计数排序
    排序算法十:桶排序
    排序算法十:桶排序
    基于MSP430F2618的程控电压源
    基于MSP430F2618的程控电压源
    Andrew Ng机器学习课程11之使用machine learning的建议
    Andrew Ng机器学习课程11之使用machine learning的建议
  • 原文地址:https://www.cnblogs.com/Chen-Jr/p/11007150.html
Copyright © 2011-2022 走看看