题解 - 路径统计

题目描述

小W所在城市有n个学校(编号从1到n),学校与学校之间用一些双向道路连接。我们已知任意两个学校一定是可以相互导到达的(直接或间接)。
现在有两个学校a和b(1≤a,b≤n,a≠b)。假如当前有两个学校x和y(x≠a,x≠b,y≠a,y≠b),如果我们要从x走到y一定会经过a和b(经过a,b的顺序没有关系),那么我们就把这个x和y称为一个神奇的点对,注意x和y交换顺序也只能作为同一个点对。
现在,小W很好奇,他想要知道在这个城市里,这样的神奇点对有多少?
你的任务就是帮小W来统计这些神奇的点对。

输入

输入一行有4个正整数n,m,a,b,分别表示学校的数量,双向道路的数量还有两个特殊的学校a和b。
接下来有m行,每行两个整数vi和ui,表示ui和vi之间有一条双向道路,保证没有重复的边,也没有自环。

输出

输出一定要经过学校a和b的神奇的点对的数量。

样例

样例输入

【样例1】
7 7 3 5
1 2
2 3
3 4
4 5
5 6
6 7
7 5
【样例2】
4 5 2 3
1 2
2 3
3 4
4 1
4 2
【样例3】
4 3 2 1
1 2
2 3
4 1

样例输出

【样例1】
4
【样例2】
0
【样例3】
1

提示

样例1中,(1,6),(1,7),(2,6),(2,7)都是神奇的点对,因为它们相互到达一定会经过3和5。
样例2中,没有点对一定会经过2和3。
样例3中,只有点对(3,4)一定要经过1和2。
对于所有数据,1≤n≤100000,1≤a,b≤n,1≤m≤200000,a≠b,ui≠vi,所有的道路均不相同。

分析

若从x走到y一定会经过a和b(经过a,b的顺序没有关系),那么称x和y为一个神奇的点对(x和y交换顺序也只能作为同一个点对),求神奇点对的数量

对a,b分别跑一边dfs,分别求出 只能通过a前往b只能通过b前往a 的点的数量,两者的乘积即为答案

代码

#pragma GCC optimize(2)
  
#include<bits/stdc++.h>
   
using namespace std;
   
typedef long long LL;
   
const int N = 100000 + 10,M = 200000 + 10;
 
int n,m,a,b;
int h[N],e[M * 2],ne[M * 2],idx;
bool st[N][2];
int cnt[2];
 
void add(int a,int b){
    e[idx] = b,ne[idx] = h[a],h[a] = idx++;
}
 
void dfs(int u,int op){
    st[u][op] = true;
    cnt[op]++;
    for(int i = h[u];i != -1;i = ne[i]){
        int j = e[i];
        if(!st[j][op]) dfs(j,op);
    }
}
 
int main(){
    ios::sync_with_stdio(false);
    cin.tie(0),cout.tie(0);
 
    memset(h,-1,sizeof h);
     
    cin >> n >> m >> a >> b;
    for(int i = 1,u,v;i <= m;i++){
        cin >> u >> v;
        add(u,v),add(v,u);
    }
 
    st[a][0] = true;
    dfs(b,0);
    st[b][1] = true;
    dfs(a,1);
 
    int tmp = 0;
    for(int i = 1;i <= n;i++)
        if(st[i][0] && st[i][1]) tmp++;
 
    cout << (cnt[0] - tmp + 1) * (cnt[1] - tmp + 1);
 
    return 0;
}
题目描述: 给定一些文件夹和文件,要求将它们按照层级关系输出成一个树形结构。 输入格式: 输入的第一行包含一个整数 n,表示文件夹和文件的个数。 接下来 n 行,每行包含一个字符串,表示一个文件夹或者文件。 其中,文件名和文件夹名都不包含空格和斜杠,文件名包含一个小数点,表示文件后缀。 输出格式: 输出一个树形结构,每行表示一个文件夹或者文件,按照层级关系缩进,文件夹名称后面要加上一个斜杠。 注意,最后一个文件夹或者文件名称后面不能有空格。 样例: 输入: 6 /root /etc /root/abcd.txt /root/bcd/ /etc/test/ /root/bcd/efg.txt 输出: /root /abcd.txt /bcd/ /efg.txt /etc /test/ 算法1 (模拟) $O(n)$ 思路: 本题需要我们输出文件夹和文件的层级结构,因此可以考虑使用哈希表记录每个文件夹和文件的层级结构。 对于每个文件夹和文件,我们可以通过判断其路径中"/"的数量来确定其所在的层级结构,具体来说,每个"/"表示一层。因此,我们可以将路径按"/"分开,然后统计"/"的数量,就可以得到该文件夹或文件所在的层级结构。 同时,由于本题要求输出树形结构,因此我们需要对每个文件夹和文件进行缩进处理,使其在输出时具有层级关系。具体来说,我们可以通过其所在的层级结构来确定输出时需要添加的缩进空格数量。 最后,我们可以按照文件夹和文件的层级结构从小到大的顺序进行输出,这样能够保证每个文件夹和文件的父节点已经被输出过了。 时间复杂度 哈希表的查询和插入操作都是常数级别的,因此总时间复杂度为 $O(n)$。 C++ 代码 算法2 (模拟) $O(nlogn)$ 思路: 本题可以使用字典树来实现,具体来说,我们可以将每个文件夹和文件的路径看作一个字符串,然后将所有字符串插入到字典树中。 同时,我们可以定义一个结构体,用来存储每个字符串的层级结构和缩进空格数量,具体来说,每个字符串的层级结构可以通过其在字典树中的深度来确定,而每个字符串的缩进空格数量则可以通过其所在的层级结构来确定。 最后,我们可以按照字符串的层级结构从小到大的顺序进行输出,这样能够保证每个字符串的父节点已经被输出过了。 时间复杂度 插入字符串的时间复杂度为 $O(nlogn)$,输出字符串的时间复杂度也为 $O(nlogn)$,因此总时间复杂度为 $O(nlogn)$。 C++ 代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值