Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始、点 v 结束的路径)。
为了方便,点用 1,2,…,n 编号。 设 count(x,y) 表示点 x 到点 y 不同的路径数量(规定 count(x,x)=0),Bobo 想知道
除以 (10 9+7) 的余数。
其中,a i,b j 是给定的数列。
Input
输入包含不超过 15 组数据。
每组数据的第一行包含两个整数 n,m (1≤n,m≤10 5).
接下来 n 行的第 i 行包含两个整数 a i,b i (0≤a i,b i≤10 9).
最后 m 行的第 i 行包含两个整数 u i,v i,代表一条从点 u i 到 v i 的边 (1≤u i,vi≤n)。
Output对于每组数据,输出一个整数表示要求的值。Sample Input
3 3 1 1 1 1 1 1 1 2 1 3 2 3 2 2 1 0 0 2 1 2 1 2 2 1 500000000 0 0 500000000 1 2
Sample Output
4 4 250000014
Hint
思路:
由有向图拓扑序的性质可以知道,拓扑序在后的节点是没有指向拓扑序在前的节点。
那么我们在对整个图进行拓扑的时候,把起始点 x 的a[x] 值 附加到 这个边的终点 y 的a[y] 值上。
并且对于每一个边,我们维护一个 long long 类型的 答案 ans,ans+= a[x]*b[y] ( 边 是 x ~> y )
那么这里就介绍刚刚我们为什么要附加数值a[x] 到a[y]上。
如果由三个点 x y z ,由如下的连接关系 x ~> y ~> z 那么x到y的边我们会算一次对答案的贡献值,y到z的边我们也会算一次。
还有一个x到z的边,我们仍然需要算。因为x可以到达z,那么如果我们在拓扑的时候把a[y]加上a[x] 时, 我们在算 b到z 的边的时候就顺便的加上了a到z的边。
因为x 的拓扑优先级比y高,并且x可以到达y,那么x就可以到达y能到达的所有边,那么就解释了这样做的原因。
这样做的时间复杂度就会转化为 O ( N )
主要是理解后就很好写代码,可以自己动手画图理解一下上面 讲的内容。
实现细节见ac代码:
#include <iostream> #include <cstdio> #include <cstring> #include <algorithm> #include <cmath> #include <queue> #include <stack> #include <map> #include <set> #include <vector> #include <iomanip> #define ALL(x) (x).begin(), (x).end() #define rt return #define dll(x) scanf("%I64d",&x) #define xll(x) printf("%I64d\n",x) #define sz(a) int(a.size()) #define all(a) a.begin(), a.end() #define rep(i,x,n) for(int i=x;i<n;i++) #define repd(i,x,n) for(int i=x;i<=n;i++) #define pii pair<int,int> #define pll pair<long long ,long long> #define gbtb ios::sync_with_stdio(false),cin.tie(0),cout.tie(0) #define MS0(X) memset((X), 0, sizeof((X))) #define MSC0(X) memset((X), '\0', sizeof((X))) #define pb push_back #define mp make_pair #define fi first #define se second #define eps 1e-6 #define gg(x) getInt(&x) #define db(x) cout<<"== [ "<<x<<" ] =="<<endl; using namespace std; typedef long long ll; ll gcd(ll a,ll b){return b?gcd(b,a%b):a;} ll lcm(ll a,ll b){return a/gcd(a,b)*b;} ll powmod(ll a,ll b,ll MOD){ll ans=1;while(b){if(b%2)ans=ans*a%MOD;a=a*a%MOD;b/=2;}return ans;} inline void getInt(int* p); const int maxn=100010; const int inf=0x3f3f3f3f; /*** TEMPLATE CODE * * STARTS HERE ***/ std::vector<int> son[maxn]; const ll mod=1e9+7ll; ll ans=0ll; ll a[maxn]; ll b[maxn]; ll num[maxn]; int du[maxn]; int main() {// freopen("D:\\common_text\\code_stream\\in.txt","r",stdin);//freopen("D:\\common_text\\code_stream\\out.txt","w",stdout); gbtb;int n,m;while(cin>>n>>m){repd(i,1,n){son[i].clear();}MS0(du);MS0(num);repd(i,1,n){cin>>a[i]>>b[i];}int x,y;repd(i,1,m){cin>>x>>y;son[x].push_back(y);du[y]++;}queue<int> q;repd(i,1,n){if(!du[i]){q.push(i);}}ans=0ll;while(q.size()){int temp=q.front();q.pop();for(auto x:son[temp]){ans=(ans+(a[temp]*b[x])%mod+mod)%mod;a[x]+=a[temp];a[x]=(a[x]+mod)%mod;du[x]--;if(!du[x]){q.push(x);}}}cout<<ans<<endl;}return 0; }inline void getInt(int* p) {char ch;do {ch = getchar();} while (ch == ' ' || ch == '\n');if (ch == '-') {*p = -(getchar() - '0');while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 - ch + '0';}}else {*p = ch - '0';while ((ch = getchar()) >= '0' && ch <= '9') {*p = *p * 10 + ch - '0';}} }