CF1454 E. Number of Simple Paths (基环树 拓扑排序)

简介: CF1454 E. Number of Simple Paths (基环树 拓扑排序)

原题链接

题意:

给定一个n个点n条边的树,求树上简单路径的数量。

思路:

N个点N条边的连通无向图,即在树上加一条边恰好包含一个环的图,称为基环树。

树上两点的路径是唯一确定的。

拓扑排序可以用来判断有向图是否有环。

代码:

#pragma GCC optimize(3)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll,ll>PLL;
typedef pair<int,int>PII;
typedef pair<double,double>PDD;
#define I_int ll
inline ll read()
{
    ll 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*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
char F[200];
inline void out(I_int x)
{
    if (x == 0) return (void) (putchar('0'));
    I_int tmp = x > 0 ? x : -x;
    if (x < 0) putchar('-');
    int cnt = 0;
    while (tmp > 0)
    {
        F[cnt++] = tmp % 10 + '0';
        tmp /= 10;
    }
    while (cnt > 0) putchar(F[--cnt]);
    //cout<<" ";
}
ll ksm(ll a,ll b,ll p)
{
    ll res=1;
    while(b)
    {
        if(b&1)res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
const int inf=0x3f3f3f3f,mod=1e9+7;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const int maxn=2e5+7,N=1e7+10;
const double PI = atan(1.0)*4;
const double eps=1e-6;
int h[maxn],idx;
struct node
{
    int e,ne;
} edge[maxn*2];
int din[maxn];
void add(int u,int v) ///存储边
{
    edge[idx]= {v,h[u]};
    h[u]=idx++;
}
queue<int>q;
bool st[maxn];
void topsort() ///变形拓扑排序求无向图的环
{
    while(!q.empty())
    {
        int u=q.front();
        q.pop();
        st[u]=1;
        for(int i=h[u]; ~i; i=edge[i].ne)
        {
            int j=edge[i].e;
            if(--din[j]==1) q.push(j);
        }
    }
}
int dfs(int u,int fa) ///求子树大小
{
    int res=1;
    for(int i=h[u]; ~i; i=edge[i].ne)
    {
        int j=edge[i].e;
        if(j==fa||!st[j]) continue;
        res+=dfs(j,u);
    }
    return res;
}
void init()///初始化
{
    memset(h,-1,sizeof h);
    memset(st,0,sizeof st);
    memset(din,0,sizeof din);
    idx=0;
    while(!q.empty()) q.pop();
}
int main()
{
    int t=read();
    while(t--)
    {
        init();
        int n=read();
        for(int i=1; i<=n; i++)
        {
            int u=read(),v=read();
            add(u,v);
            add(v,u);
            din[u]++;
            din[v]++;
        }
        ///求环
        for(int i=1; i<=n; i++)
            if(din[i]==1) q.push(i);
        topsort();
        ll res=1ll*n*(n-1);
        for(int i=1; i<=n; i++)
            if(!st[i])
            {
                ll tmp=dfs(i,i);
                res=res-(tmp-1)*tmp/2;
            }
        printf("%lld\n",res);
    }
    return 0;
}
目录
相关文章
|
算法
Leetcode 313. Super Ugly Number
题目翻译成中文是『超级丑数』,啥叫丑数?丑数就是素因子只有2,3,5的数,7 14 21不是丑数,因为他们都有7这个素数。 这里的超级丑数只是对丑数的一个扩展,超级丑数的素因子不再仅限于2 3 5,而是由题目给定一个素数数组。与朴素丑数算法相比,只是将素因子变了而已,解法还是和朴素丑数一致的。
98 1
|
5月前
|
存储 SQL 算法
LeetCode 题目 65:有效数字(Valid Number)【python】
LeetCode 题目 65:有效数字(Valid Number)【python】
|
6月前
|
存储 算法
【LeetCode力扣】单调栈解决Next Greater Number(下一个更大值)问题
【LeetCode力扣】单调栈解决Next Greater Number(下一个更大值)问题
43 0
|
存储
Leetcode Single Number II (面试题推荐)
给你一个整数数组,每个元素出现了三次,但只有一个元素出现了一次,让你找出这个数,要求线性的时间复杂度,不使用额外空间。
39 0
|
算法
LeetCode 414. Third Maximum Number
给定一个非空数组,返回此数组中第三大的数。如果不存在,则返回数组中最大的数。要求算法时间复杂度必须是O(n)。
94 0
LeetCode 414. Third Maximum Number
|
存储
LeetCode 313. Super Ugly Number
编写一段程序来查找第 n 个超级丑数。 超级丑数是指其所有质因数都是长度为 k 的质数列表 primes 中的正整数。
96 0
LeetCode 313. Super Ugly Number
|
算法
LeetCode 306. Additive Number
累加数是一个字符串,组成它的数字可以形成累加序列。 一个有效的累加序列必须至少包含 3 个数。除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和。 给定一个只包含数字 '0'-'9' 的字符串,编写一个算法来判断给定输入是否是累加数。 说明: 累加序列里的数不会以 0 开头,所以不会出现 1, 2, 03 或者 1, 02, 3 的情况。
122 0
LeetCode 306. Additive Number
|
算法
LeetCode 268. Missing Number
给定一个包含 0, 1, 2, ..., n 中 n 个数的序列,找出 0 .. n 中没有出现在序列中的那个数。
89 0
LeetCode 268. Missing Number