[Nowcoder] 有向无环图 | 拓扑排序简单应用

链接

题目描述

Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始、点 v 结束的路径)。
为了方便,点用 1 , 2 , … , n 1, 2, \dots, n 1,2,,n编号。
c o u n t ( x , y ) \mathrm{count}(x, y) count(x,y) 表示点 x 到点 y 不同的路径数量(规定 c o u n t ( x , x ) = 0 \mathrm{count}(x, x) = 0 count(x,x)=0,Bobo 想知道
∑ i = 1 n ∑ j = 1 n c o u n t ( i , j ) ⋅ a i ⋅ b j \sum_{i = 1}^n\sum_{j = 1}^n \mathrm{count}(i, j) \cdot a_i \cdot b_j i=1nj=1ncount(i,j)aibj
除以 ( 1 0 9 + 7 ) (10^9+7) (109+7) 的余数。
其中, a i , b j a_i, b_j ai,bj是给定的数列。

输入描述:

输入包含不超过 15 组数据。
每组数据的第一行包含两个整数 n, m ( 1 ≤ n , m ≤ 1 0 5 1 \leq n, m \leq 10^5 1n,m105)
接下来 n 行的第 i 行包含两个整数 a i , b i a_i, b_i ai,bi
( 0 ≤ a i , b i ≤ 1 0 9 (0 \leq a_i, b_i \leq 10^9 (0ai,bi109 ).
最后 m 行的第 i 行包含两个整数 u i , v i u_i, v_i ui,vi ,代表一条从点 u i u_i ui v i v_i vi的边 ( 1 ≤ u i , v i ≤ n ) (1 \leq u_i, v_i \leq n) (1ui,vin)
输出描述:
对于每组数据,输出一个整数表示要求的值。
示例1
输入

3 3
1 1
1 1
1 1
1 2
1 3
2 3

输出

4

示例2
输入

2 2
1 0
0 2
1 2
1 2

输出

4

示例3
输入

2 1
500000000 0
0 500000000
1 2

输出

250000014

因为是DAG图,重要的是不存在环,所以说这道题我们可以通过拓扑排序来操作,在拓扑排序的过程中,先将队列里将要 p o p ( ) pop() pop()的元素 u u u加上 a [ u ] a[u] a[u],然后再从遍历所连边的时候,考虑贡献变化,然后用 r e s res res记录

#define Clear(x,val) memset(x,val,sizeof x)
struct node {
	int u,v,nex;
}e[maxn];
int n,m;
int cnt,head[maxn];
ll a[maxn],b[maxn];
int deg[maxn];
ll ans[maxn];
void init() {
	cnt = 0;
	Clear(head,-1);
	Clear(ans,0);
	Clear(deg,0);
}
void add(int u,int v){
	e[cnt].u = u;
	e[cnt].v = v;
	e[cnt].nex = head[u];
	head[u] = cnt ++;
}
ll res;
void topoSort(){
	queue<int> que;
	for(int i=1;i<=n;i++){
		if(deg[i] == 0) que.push(i);
	}
	while(que.size()){
		int u = que.front();
		que.pop();
		ans[u] = (ans[u] + a[u]) % mod;
		for(int i = head[u];~i;i = e[i].nex){
			int to = e[i].v;
			ans[to] = (ans[to] + ans[u]) % mod;
			res += ans[u] * b[to];
			res %= mod;
			-- deg[to];
			if(deg[to] == 0) que.push(to);
		}
	}
}
int main() {
	while(cin >> n >> m) {
		init();
		for(int i = 1;i <= n;i ++){
			a[i] = read,b[i] = read;
		}
		for(int i = 1;i <= m;i ++){
			int u = read,v = read;
			add(u,v);
			deg[v] ++;
		}
		res = 0;
		topoSort();
		cout << res << endl;
	}
	return 0;
}
/**


**/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值