zoukankan      html  css  js  c++  java
  • 牛客CSP-S提高组赛前集训营4 B 路径计数机

    传送门

    这道题其实不用换根(我也不会打换根)

    对于(a,b)(c,d)这两条路径,我们考虑有哪些情况:

    1. LCA(c,d)在LCA(a,b)的子树中。

    2. LCA(c,d)不在LCA(a,b)的子树中。

    对于第一种情况,我们要保证LCA(c,d)不在a到b的路径上。

    对于第二种情况,c到d的路径不经过连接LCA(a,b)和其父亲的边。

    然后就先两次dfs神奇处理出我们需要的东西,代码很好理解。(我也只能理解了)

    主要是思维很神奇。

    #include<bits/stdc++.h>
    #define LL long long
    #define N 3003
    #define re register
    using namespace std;
    int read()
    {
        int x=0,f=1;char s=getchar();
        while(s<'0'||s>'9'){if(s=='-')f=-1;s=getchar();}
        while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}
        return x*f;
    } 
    struct EDGE{
        int nextt,to;
    }w[N*2];
    int tot=0;
    int n,p,q;
    int head[N];
    LL fq[N],fp[N];//以i为lca,长度为q/p的路径数 
    LL gq[N],gp[N];//经过了i与其父亲的连边,长度为q/p的路径数 
    LL f[N][N],g[N][N];//i的子树中距离根为j的个数,不在i的子树中距离根为j的个数 
    void add(int a,int b)
    {
        tot++;
        w[tot].nextt=head[a];
        w[tot].to=b;
        head[a]=tot;
    }
    //fp,fq,gp,gq更新时均是用了乘法原理
    //要有把子树紫薯一个个丢入的前缀思想 
    void dfs1(int x,int fa)
    {
        f[x][0]=1;
        for(int i=head[x];i;i=w[i].nextt)
        {
            int v=w[i].to;
            if(v==fa)continue;
            dfs1(v,x);
            for(int j=1;j<=p;++j)fp[x]+=f[v][p-j]*f[x][j-1];
            for(int j=1;j<=q;++j)fq[x]+=f[v][q-j]*f[x][j-1];
            for(int j=1;j<=max(q,p);++j)f[x][j]+=f[v][j-1];
        }
    }
    void dfs2(int x,int fa)
    {
        for(int i=1;i<=p;++i)gp[x]+=f[x][p-i]*g[x][i];
        for(int i=1;i<=q;++i)gq[x]+=f[x][q-i]*g[x][i];
        for(int i=head[x];i;i=w[i].nextt)
        {
            int v=w[i].to;
            if(v==fa)continue;
            g[v][1]=1;
            for(int j=2;j<=max(p,q);++j)g[v][j]+=g[x][j-1]+f[x][j-1]-f[v][j-2];
            dfs2(v,x);
        }
    }
    int main()
    {
        n=read();p=read();q=read();
        for(int i=1;i<n;++i)
        {
            int a=read(),b=read();
            add(a,b);add(b,a);
        }
        dfs1(1,1);dfs2(1,1);
        LL sum1=0,sum2=0;
        for(int i=1;i<=n;++i)sum1+=fq[i],sum2+=fp[i];
        LL ans=sum1*sum2;
        for(int i=1;i<=n;++i)ans-=(fq[i]*fp[i]+fq[i]*gp[i]+fp[i]*gq[i]);
        printf("%lld
    ",ans*4);
    } 
    /*
    */
    View Code
  • 相关阅读:
    异常问题处理记录(转载篇)
    linux服务器出现大量连接:sshd: root@notty
    第4章 Python运算符
    第2章 python基础知识
    第1章 python环境搭建
    Tomcat漏洞升级
    第3章 数据类型、运算符和表达式
    第2章 C语言基础知识
    第1章 概述
    第1章 企业管理概论
  • 原文地址:https://www.cnblogs.com/yyys-/p/11808624.html
Copyright © 2011-2022 走看看