P11468 有向树

有向树

题目描述

给定一棵 n n n 个结点的树,将树上所有的无向边变成给定方向的有向边,求所有简单路径的长度之和。

有向图中 a 1 a_1 a1 a x a_x ax 的简单路径是形如 a 1 → a 2 → a 3 → ⋯ → a x a_1 \rightarrow a_2 \rightarrow a_3\rightarrow \cdots \rightarrow a_x a1a2a3ax 的路径,其中 a 1 , a 2 , a 3 , ⋯   , a x a_1,a_2,a_3,\cdots,a_x a1,a2,a3,,ax x x x 个顶点互不相同,其长度为简单路径上的有向边数量。

输入格式

第一行一个整数 n n n,表示树上一共有 n n n 个结点。

接下来 n − 1 n - 1 n1 行,每行两个整数 u , v u,v u,v,表示一条有向边 u → v u\rightarrow v uv

输出格式

一个整数,表示有向树上所有简单路径的长度之和。

样例 #1

样例输入 #1

5
1 2
1 3
1 4
1 5

样例输出 #1

4

样例 #2

样例输入 #2

5
1 2
3 1
4 1
5 1

样例输出 #2

10

样例 #3

样例输入 #3

4
1 2
2 3
3 4

样例输出 #3

10

样例 #4

样例输入 #4

6
1 2
3 2
4 3
5 3
6 3

样例输出 #4

11

提示

1 ≤ n ≤ 2 × 1 0 5 1 \le n \le 2\times 10^5 1n2×105 1 ≤ u , v ≤ n 1\le u, v \le n 1u,vn,保证输入数据的有向边在看作无向边时,图构成一棵树。

思路:

非常简单的题:拓扑排序+树上dp
反向存边然后拓扑排序过程中dp转移即可
g(u)表示以u点为起点可以到达的点的数量(不包括u本身)
f(u)表示以u点为起点的所有简单路径长度和
u → v u \rightarrow v uv 转移方程为:
g ( u ) = g ( v ) + 1 g(u)=g(v)+1 g(u)=g(v)+1
f ( u ) = f ( v ) + g ( v ) + 1 f(u)=f(v)+g(v)+1 f(u)=f(v)+g(v)+1

代码:
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
typedef long long ll;
#define FU(i, a, b) for(int i = (a); i <= (b); ++ i)
#define FD(i, a, b) for(int i = (a); i >= (b); -- i)
using namespace std;
const int N=200010;

vector<int> ljs(N);
vector<int> fj[N];
int f[N];
int g[N];

signed main() {
    cin.tie(0)->ios::sync_with_stdio(0);
    int n;
    cin>>n;
    FU(i,1,n-1){
        int a,b;
        cin>>a>>b;
        ljs[a]++;
        fj[b].push_back(a);
    }
    queue<int> x;
    FU(i,1,n){
        if(ljs[i]==0){
            x.push(i);
        }
    }
    while(!x.empty()){
        int t = x.front();
        x.pop();
        for(int e: fj[t]){
            ljs[e]--;
            if(ljs[e]==0){
                x.push(e);
            }
            g[e]+=g[t]+1;
            f[e]+=f[t]+g[t]+1;
        }
    }
    int ans = 0 ;
    FU(i,1,n){
        ans+=f[i];
    }
    cout<<ans<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值