CSU 1804

来源:互联网 发布:xy苹果助手下载mac版 编辑:程序博客网 时间:2024/06/03 23:44

1804: 有向无环图

        Time Limit: 5 Sec     Memory Limit: 128 Mb     Submitted: 732     Solved: 305    

Description

Bobo 有一个 n 个点,m 条边的有向无环图(即对于任意点 v,不存在从点 v 开始、点 v 结束的路径)。
为了方便,点用 1,2,…,n 编号。 设 count(x,y) 表示点 x 到点 y 不同的路径数量(规定 count(x,x)=0),Bobo 想知道

除以 (109+7) 的余数。
其中,ai,bj 是给定的数列。

Input

输入包含不超过 15 组数据。
每组数据的第一行包含两个整数 n,m (1≤n,m≤105).
接下来 n 行的第 i 行包含两个整数 ai,bi (0≤ai,bi≤109).
最后 m 行的第 i 行包含两个整数 ui,vi,代表一条从点 ui 到 vi 的边 (1≤ui,vi≤n)。

Output

对于每组数据,输出一个整数表示要求的值。

Sample Input

3 31 11 11 11 21 32 32 21 00 21 21 22 1500000000 00 5000000001 2

Sample Output

44250000014
#include<iostream>#include<cstring>#include<cstdio>#include<queue>#define MOD 1000000007#define MAX 100005//数组开的太大了,我用的是codeblocks导致一直运行不了,后来发现数组开大了,定义为全局变量就好,//全局变量是存储在数据区的,而局部变量是用栈存储的,栈太小,会溢出using namespace std;vector<int> list[MAX];long long a[MAX],b[MAX];int degree[MAX];long long sum[MAX];int main(){    int n,m;    while(~scanf("%d%d",&n,&m))    {        memset(degree,0,sizeof(degree));        memset(list,0,sizeof(list));        memset(sum,0,sizeof(sum));        for(int i=1; i<=n; i++)        {            scanf("%lld%lld",&a[i],&b[i]);            sum[i]=b[i];        }        for(int i=1; i<=m; i++)        {            int fa,son;            scanf("%d%d",&fa,&son);            degree[fa]++;//记录从fa出发的路径数            list[son].push_back(fa);//记录到son的点        }        queue<int> original;        queue<int> sorted;        for(int i=1; i<=n; i++)        {            if(degree[i]==0)                original.push(i);//没有出度的入队        }        while(!original.empty())//队列不为空        {            int son=original.front();//读取最底端元素            original.pop();//出队(先进先出)取出最底端元素            for(int i=0; i<list[son].size(); i++)            {                int fa=list[son][i];                degree[fa]--;                if(degree[fa]==0)                    original.push(fa);            }            sorted.push(son);        }        long long ans=0;        while(!sorted.empty())//队列不为空        {            int son=sorted.front();            sorted.pop();            /*eg:4 4                 1 1                 1 1                 1 1                 1 1                 1 2                 1 3                 2 3                 1 4                 出队的顺序是3 4 2 1                 这样子的话首先计算的是以3为终点的路径,分别是1->3,2->3                 1->3:ans=ans+a[1]*b[3]=1;b[1]=b[1]+b[3]=2;                 2->3:ans=ans+a[2]*b[3]=2;b[2]=b[2]+b[3]=2;                 接着就是                 1->4:ans=ans+a[1]*b[4]=3;b[1]=b[1]+b[4]=3;                 然后                 1->2:ans=ans+a[1]*b[2]=5;b[1]=b[1]+b[2]=5;                 从数据可以看出算1->2的时候其实是这样子算的,首先加上原来累加的,其次b[2]=b[2]+b[3],这样是因为1->2->3                 也可以这样子认为1->3的时候只计算了一次b[3],到1->2的时候要多加一个b[3],这个地方一开始想错了,以至于钻了好久的牛角尖,                 还是得自己慢慢领悟吧!            */            for(int i=0; i<list[son].size(); i++)            {                int fa=list[son][i];                ans=(ans+(a[fa]*sum[son])%MOD)%MOD;                sum[fa]=(sum[fa]+sum[son])%MOD;            }        }        printf("%lld\n",ans%MOD);    }    return 0;}