Tarjan(强连通分量) - Checkposts - CodeForces 427C
题意:
给 定 一 个 n 个 点 , m 条 边 的 有 向 图 , 给定一个n个点,m条边的有向图, 给定一个n个点,m条边的有向图,
现 在 要 在 某 些 点 上 设 置 警 察 局 , 在 i 点 设 置 警 察 局 的 代 价 为 w i , 现在要在某些点上设置警察局,在i点设置警察局的代价为w_i, 现在要在某些点上设置警察局,在i点设置警察局的代价为wi,
i 点 的 警 察 局 能 够 保 护 j 点 , 当 且 仅 当 i 和 j 之 间 能 够 双 向 到 达 ( i 能 到 j , j 也 能 到 i ) 。 i点的警察局能够保护j点,当且仅当i和j之间能够双向到达(i能到j,j也能到i)。 i点的警察局能够保护j点,当且仅当i和j之间能够双向到达(i能到j,j也能到i)。
现 在 要 计 算 最 少 花 费 , 使 得 所 有 的 点 都 能 够 被 警 察 局 保 护 到 。 并 计 算 最 少 花 费 的 不 同 方 案 总 数 , 结 果 对 1 0 9 + 7 取 模 。 现在要计算最少花费,使得所有的点都能够被警察局保护到。并计算最少花费的不同方案总数,结果对10^9+7取模。 现在要计算最少花费,使得所有的点都能够被警察局保护到。并计算最少花费的不同方案总数,结果对109+7取模。
当 两 个 方 案 中 存 在 一 个 警 察 局 设 置 的 位 置 不 同 , 两 个 方 案 被 认 为 是 不 同 的 当两个方案中存在一个警察局设置的位置不同,两个方案被认为是不同的 当两个方案中存在一个警察局设置的位置不同,两个方案被认为是不同的
输入:
首 行 一 个 正 整 数 n , 首行一个正整数n, 首行一个正整数n,
接 着 一 行 n 个 整 数 , w 1 , w 2 , . . . , w n 。 接着一行n个整数,w_1,w_2,...,w_n。 接着一行n个整数,w1,w2,...,wn。
然 后 输 入 正 整 数 m , 然后输入正整数m, 然后输入正整数m,
最 后 m 行 表 示 m 条 边 , 每 行 两 个 正 整 数 u i , v i , 表 示 点 u i 和 v i 之 间 有 一 条 有 向 边 。 最后m行表示m条边,每行两个正整数u_i,v_i,表示点u_i和v_i之间有一条有向边。 最后m行表示m条边,每行两个正整数ui,vi,表示点ui和vi之间有一条有向边。
输出:
两 个 正 整 数 , 分 别 表 示 最 小 花 费 和 最 小 花 费 的 不 同 方 案 总 数 。 两个正整数,分别表示最小花费和最小花费的不同方案总数。 两个正整数,分别表示最小花费和最小花费的不同方案总数。
Examples
Input
3
1 2 3
3
1 2
2 3
3 2
Output
3 1
Input
5
2 8 0 6 0
6
1 4
1 3
2 4
3 4
4 5
5 1
Output
8 2
Input
10
1 3 2 2 1 3 1 4 10 10
12
1 2
2 3
3 1
3 4
4 5
5 6
5 7
6 4
7 3
8 9
9 10
10 9
Output
15 6
Input
2
7 91
2
1 2
2 1
Output
7 1
数据范围:
1 ≤ n ≤ 1 0 5 , 0 ≤ m ≤ 3 ⋅ 1 0 5 , 0 ≤ w i ≤ 1 0 9 , 1 ≤ u i , v i ≤ n ; u ≠ v 1 ≤ n ≤ 10^5,0 ≤ m ≤ 3·10^5,0≤w_i≤10^9,1 ≤ u_i, v_i ≤ n; u ≠ v 1 ≤ n ≤ 105,0 ≤ m ≤ 3⋅105,0≤wi≤109,1 ≤ ui, vi ≤ n;u = v
分析:
由 题 意 , 要 使 得 总 花 费 最 小 , 就 要 使 得 每 个 强 连 通 分 量 的 化 费 最 小 。 由题意,要使得总花费最小,就要使得每个强连通分量的化费最小。 由题意,要使得总花费最小,就要使得每个强连通分量的化费最小。
首 先 通 过 t a r j a n 算 法 求 强 连 通 分 量 , 同 时 维 护 两 个 数 组 m i n p 和 c n t _ m i n p , 首先通过tarjan算法求强连通分量,同时维护两个数组minp和cnt\_minp, 首先通过tarjan算法求强连通分量,同时维护两个数组minp和cnt_minp,
分 别 表 示 每 个 强 连 通 块 内 部 所 有 点 中 的 最 小 点 权 , 和 最 小 点 权 的 数 量 。 分别表示每个强连通块内部所有点中的最小点权,和最小点权的数量。 分别表示每个强连通块内部所有点中的最小点权,和最小点权的数量。
则 总 的 最 少 花 费 为 : ∑ i = 1 s s c _ c n t m i n p [ i ] , 其 中 s s c _ c n t 表 示 强 连 通 块 的 数 量 。 则总的最少花费为:\sum_{i=1}^{ssc\_cnt}minp[i],其中ssc\_cnt表示强连通块的数量。 则总的最少花费为:∑i=1ssc_cntminp[i],其中ssc_cnt表示强连通块的数量。
根 据 乘 法 原 理 , 最 少 花 费 的 不 同 方 案 总 数 为 : ∏ i = 1 s s c _ c n t c n t _ m i n p [ i ] 。 根据乘法原理,最少花费的不同方案总数为:\prod_{i=1}^{ssc\_cnt}cnt\_minp[i]。 根据乘法原理,最少花费的不同方案总数为:∏i=1ssc_cntcnt_minp[i]。
代码:
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=100010, M=300010, mod=1e9+7;
int n,m;
int e[M],ne[M],h[N],w[N],idx;
int stk[N],top;
bool in_stk[N];
int id[N],ssc_cnt;
int dfn[N],low[N],timestamp;
int minp[N],cnt_minp[N];
void add(int a,int b)
{
e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void tarjan(int u)
{
dfn[u]=low[u]=++timestamp;
stk[++top]=u,in_stk[u]=true;
for(int i=h[u];~i;i=ne[i])
{
int j=e[i];
if(!dfn[j])
{
tarjan(j);
low[u]=min(low[u],low[j]);
}
else if(in_stk[j]) low[u]=min(low[u],dfn[j]);
}
if(dfn[u]==low[u])
{
++ssc_cnt;
int y;
do
{
y=stk[top--];
in_stk[y]=false;
id[y]=ssc_cnt;
if(minp[ssc_cnt]>w[y]) minp[ssc_cnt]=w[y], cnt_minp[ssc_cnt]=1;
else if(minp[ssc_cnt]==w[y]) cnt_minp[ssc_cnt]++;
}while(y!=u);
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&w[i]);
cin>>m;
memset(h,-1,sizeof h);
for(int i=0;i<m;i++)
{
int a,b;
scanf("%d%d",&a,&b);
add(a,b);
}
memset(minp,0x3f,sizeof minp);
for(int i=1;i<=n;i++)
if(!dfn[i])
tarjan(i);
ll res1=0, res2=1;
for(int i=1;i<=ssc_cnt;i++)
{
res1+=minp[i];
res2=(ll)res2*cnt_minp[i]%mod;
}
cout<<res1<<' '<<res2<<endl;
return 0;
}