zoukankan      html  css  js  c++  java
  • P3258 [JLOI2014]松鼠的新家

    传送门

    此题树剖可过

    然而可以树上差分为什么要树剖..

    对于一条路径(A,B),只要把 val [ A ] ++ , val [ B ] ++ , val [ LCA(A,B) ] -- , val [ fa[LCA(A,B)] ] --

    那么求每个点的经过次数就求一下子树 val 的和就好了

    但是要注意,每一条路径的终点是下一条路径的起点,那些点会被多算一次

    所以求完子树和以后要再把那些点 val--

    代码很简单

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cmath>
    #include<cstring>
    using namespace std;
    const int N=6e5+7;
    inline int read()
    {
        int x=0,f=1; char ch=getchar();
        while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
        while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
        return x*f;
    }
    
    int fir[N],from[N<<1],to[N<<1],cnt;
    inline void add(int &a,int &b)
    {
        from[++cnt]=fir[a];
        fir[a]=cnt; to[cnt]=b;
    }
    
    int n;
    
    int dep[N],f[N][27];//LCA的数组
    void dfs1(int x,int fa)//dfs1预处理f和dep
    {
        f[x][0]=fa; dep[x]=dep[fa]+1;
        for(int i=1;(1<<i)<=dep[x];i++) f[x][i]=f[f[x][i-1]][i-1];
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i]; if(v==fa) continue;
            dfs1(v,x);
        }
    }
    inline int LCA(int x,int y)//求LCA
    {
        if(dep[x]<dep[y]) swap(x,y);
        for(int i=20;i>=0;i--) if(dep[f[x][i]]>=dep[y]) x=f[x][i];
        if(x==y) return x;
        for(int i=20;i>=0;i--)
            if(f[x][i]!=f[y][i]) x=f[x][i],y=f[y][i];
        return f[x][0];
    }
    
    int a[N],sum[N];
    void dfs2(int x)//dfs2求子树和
    {
        for(int i=fir[x];i;i=from[i])
        {
            int &v=to[i]; if(v==f[x][0]) continue;
            dfs2(v); sum[x]+=sum[v];
        }
    }
    int main()
    {
        int b,c;
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<n;i++) b=read(),c=read(),add(b,c),add(c,b);
        dfs1(1,1);
        int t;
        for(int i=1;i<n;i++)
        {
            sum[a[i]]++; sum[a[i+1]]++;
            t=LCA(a[i],a[i+1]);
            sum[t]--; if(t!=1) sum[f[t][0]]--;//注意细节
        }
        dfs2(1);
        for(int i=2;i<=n;i++) sum[a[i]]--;//减去重复算的
        for(int i=1;i<=n;i++)
            printf("%d
    ",sum[i]);
        return 0;
    }
  • 相关阅读:
    《图解CSS3》笔记5 媒体与Responsive设计
    理论篇 前端MVC、MVP、MVVM思考1
    AngularJS篇 $resource使用笔记
    《图解CSS3》笔记4 animation动画
    Prim
    邻接矩阵与邻接表
    差分约束
    SPFA
    floyd
    Kosaraju
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9790381.html
Copyright © 2011-2022 走看看