敌敌_ssl2541_dfs

66 篇文章 0 订阅

Description


月考刚考了年级倒数的敌敌来到电脑室,朝着正在写树套树套树套树的beginend大吼:我就不信我有辣么辣鸡!我可是去年普及组AC了第一题的人啊!
beginend不耐烦地扔了一道题给敌敌,然后说:你只要把这道题写出来你就不是辣鸡啦。
敌敌接过题一看,题目是这样的:
有n个点和n-1条无向边,满足任意两点都可以互相到达,求有多少条经过且仅经过三个点的简单路径。
(简单路径即为每个点最多被访问一次的路径)
但是敌敌发现自己并不会写这题,但又不愿承认自己是辣鸡这个事实,于是他就拿着题目来找刚刚成为保送狗的你。为了敌敌的智商,你只好选择了帮他一把。

Input


第一行一个正整数n表示城市数量。
接下来n-1行每行两个正整数u,v表示u和v之间有一条道路。

Output


输出一行,表示经过且仅经过三个点的简单路径的数量。

[数据范围与约定]


对于 30%的数据 n<=20
对于 60%的数据 n<=200
对于 100%的数据 n<=200000

Source


beginend

Analysis


幂痿大变态!!
明显是树图片,直接dfs,记录i节点的儿子个数 son[i][0] 和孙子个数 son[i][1] ,那么经过这个节点的路径条数为

son[i][1]+son[i][0](son[i][0]1)2

然后路径是双向的,要算两倍
良心数据没爆栈

Code


#include <iostream>
#define M 200001
using namespace std;
struct edge {int y,next;}e[M*2+1];
int son[M][2],ls[M*2+1],maxE=0,ans=0;
bool vis[M];
void add(int x,int y){e[++maxE]=(edge){y,ls[x]};ls[x]=maxE;}
void dfs(int x)
{
    vis[x]=true;
    for (int i=ls[x];i;i=e[i].next)
    if (!vis[e[i].y])
        {
            dfs(e[i].y);
            son[x][0]++;
            son[x][1]+=son[e[i].y][0];
        }
    ans+=son[x][0]*(son[x][0]-1);
    ans+=son[x][1]*2;
}
int main()
{
    ios::sync_with_stdio(false);
    int root=0,n;
    cin>>n;
    for (int i=1;i<n;i++)
    {
        int x,y;
        cin>>x>>y;
        add(x,y);
        add(y,x);
        if (!root)
            root=x;
    }
    dfs(root);
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值