zoukankan      html  css  js  c++  java
  • [数学] JZOJ P3636 分叉

    Description

    给出一棵N 个点的树,点的编号是1, 2,。。。,N。
    对于3 个点{a,b,c},如果不存在一条简单路径同时经过a,b,c,那么{a,b,c}是一个分叉。
    统计不同分叉的数量。
    树 无环,连通的无向图
    简单路径 不重复经过同一个点的路径

    Input

    第1 行,1 个整数N。接下来(N -1) 行,每行2 个整数Ai,Bi,表示点Ai 和点Bi 间有一条边。

    Output

    1 个整数,表示所求的值。

    Sample Input

    5

    1 2

    1 3

    1 4

    1 5

    Sample Output

    4

    Data Constraint

    • 对于30% 的数据,N <= 100;

    • 对于50% 的数据,N <= 1000;

    • 对于100% 的数据,1 <= N <= 10^5。

    题解

    我们可以统计出每个节点的子树大小
    然后,可以换一种方法想:我们求出所有可能的C(n,3)-可以用简单路径连成的点=不可以的点
    题目说没有重复的情况出现,那么对于一个节点作“中转站”的情况下,是存在有
    这里写图片描述
    然后我们每次换根,求下一个节点可以求出的和

    代码

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int zs[200010],father[200010],last[400010],head[200010],next[400010],n,tot,a[200010],b[200010];
    long long ans,num;
    void insert(int x,int y)
    {
        last[++tot]=y;
        next[tot]=head[x];
        head[x]=tot;
    }
    void find (int x)
    {
        zs[x]=1;
        for (int i=head[x];i;i=next[i])
            if (last[i]!=father[x])
            {
                father[last[i]]=x;
                find(last[i]);
                zs[x]+=zs[last[i]]; 
            }
    }
    void dfs (int x)
    {
        num=0;
        for(int i=head[x];i;i=next[i])
        {
            ans+=(long long)num*zs[last[i]];
            num+=zs[last[i]];
        }
        a[x]=zs[x];
        for (int i=head[x];i;i=next[i])
            if (last[i]!=father[x])
            {
                zs[x]=a[x];
                b[x]=zs[last[i]];
                zs[x]-=zs[last[i]];
                zs[last[i]]+=zs[x];
                dfs(last[i]);
                zs[last[i]]=b[x];
            }
    }
    int main()
    {
        freopen("fork.in","r",stdin);
        freopen("fork.out","w",stdout);
        scanf("%d",&n);
        int x,y;
        for (int i=1;i<=n-1;i++)
        {
            scanf("%d%d",&x,&y);
            insert(x,y);
            insert(y,x);
        }
        find(1);
        dfs(1);
        long long sum=(long long)n*(n-1)*(n-2)/6;
        printf("%lld",sum-ans);
        return 0;
    }
  • 相关阅读:
    Python:如何显示进度条
    Python:常用函数封装
    Javascript:常用函数封装
    Javascript:alert(1)可以这样写以绕过filter
    SQL注入备忘单
    Web渗透:PHP字符编码绕过漏洞总结
    SQLi Lab的视频教程和文字教程
    Python:使用基于事件驱动的SAX解析XML
    Python:渗透测试开源项目【源码值得精读】
    Python:SQLMap源码精读—start函数
  • 原文地址:https://www.cnblogs.com/Comfortable/p/8412232.html
Copyright © 2011-2022 走看看