zoukankan      html  css  js  c++  java
  • 2020 CCPC Wannafly Winter Camp Day1 Div.1&2 E树与路径(等差数列树上差分)

    题:https://ac.nowcoder.com/acm/contest/3979/E

    题意:题清

    分析:对于单单一个点考虑(这里我们用节点1),我们可以o(n)算出其答案,那么考虑换根后的答案是多少

       考虑u->v,显然,要是一条路径(s,t)只有同时经过u和v答案才会变,其余路径不会对答案造成影响

       设x为lca(s,t)到s的距离,那么这条路径对u的贡献为x(dis(s,t)-x),而对v的贡献为(x-1)(dis(s,t)-(x-1)),展开后我们就可以找到转移后答案变换了+2x-dis(s,t)-1;

       dis(s,t)-1为常量,2*x会随着向上走而增加(为等差数列),所以用树上差分来处理

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    #define pb push_back
    const int inf=0x3f3f3f3f;
    const ll INF=1e18;
    const int M=3e5+5;
    ll deep[M],ans[M];
    int sz[M],son[M],fa[M],tp[M];
    vector<int>g[M];
    struct node{
        ll p,q;
        node(ll pp=0,ll qq=0):p(pp),q(qq){}
    }a[M];
    void dfs1(int u,int f){
        deep[u]=deep[f]+1,fa[u]=f,sz[u]=1;
        for(auto v:g[u]){
            if(v!=f){
                dfs1(v,u);
                sz[u]+=sz[v];
                if(sz[son[u]]<sz[v])
                    son[u]=v;
            }
        }
    }
    void dfs2(int u,int top){
        tp[u]=top;
        if(son[u])
            dfs2(son[u],top);
        for(auto v:g[u]){
            if(v!=fa[u]&&v!=son[u])
                dfs2(v,v);
        }
    }
    int LCA(int x,int y){
        while(tp[x]!=tp[y]){
            if(deep[tp[x]]>deep[tp[y]])
                x=fa[tp[x]];
            else
                y=fa[tp[y]];
        }
        return deep[x]>deep[y]?y:x;
    }
    void dfs3(int u){
        for(auto v:g[u]){
            if(v!=fa[u]){
                dfs3(v);
                a[u].p+=a[v].p;
                a[u].q+=a[v].q;
            }
        }
        a[u].p-=2ll*a[u].q;///等差
    }
    void dfs4(int u,ll now){
        ans[u]=now;
        for(auto v:g[u]){
            if(v!=fa[u])
                dfs4(v,now-a[v].p);
        }
    }
    int main(){
        int n,m;
        scanf("%d%d",&n,&m);
        for(int u,v,i=1;i<n;i++){
            scanf("%d%d",&u,&v);
            g[u].pb(v);
            g[v].pb(u);
        }
        dfs1(1,0);
        dfs2(1,1);
        ll num=0;
        while(m--){
            int u,v;
            scanf("%d%d",&u,&v);
            int lca=LCA(u,v);
            int dis=deep[u]+deep[v]-2ll*deep[lca];
    
            a[u].p+=(dis+1);///dis+1部分
            a[u].q+=1;///x部分
            a[lca].p-=(dis+1-2ll*(deep[u]-deep[lca]));///边差分,全减掉
            a[lca].q-=1;
            ///
            a[v].p+=(dis+1),a[v].q+=1;
            a[lca].p-=(dis+1-2ll*(deep[v]-deep[lca])),a[lca].q-=1;
            ///
            num+=(deep[u]-deep[lca])*(deep[v]-deep[lca]);
        }
        dfs3(1);
        dfs4(1,num);
        for(int i=1;i<=n;i++)
            printf("%lld
    ",ans[i]);
        return 0;
    }
    View Code
  • 相关阅读:
    考察数据结构(An Extensive Examination of Data Structures)
    考察数据结构——第一部分:数据结构简介[译]
    老生常谈
    使用DataSet的ReadXml和WriteXml方法
    要掌握Sql Server,我还差得远啊!
    新浪短信Web Service
    还是水晶报表
    两种报表组件的功能分析
    无限级分类(非递归算法/存储过程版/GUID主键)完整数据库示例_(4)显示记录
    c#方法中调用参数的值传递方式和引用传递方式,以及ref与out的区别
  • 原文地址:https://www.cnblogs.com/starve/p/12835395.html
Copyright © 2011-2022 走看看