/*
这道题的思路是使用利用优先队列将字典序作为第一关键字,将普通拓扑排序中的判定入度等于零变成入度小于等于k即可,但是如果每一次排出来一个就从新扫一遍也未免太慢,必爆的节奏(^o^)/~所以我们使用一种诡异优化来解决这个问题:
*/
#include<iostream>
#include<algorithm>
#include<queue>
#include<cstdio>
#include<cstring>
using namespace std;
priority_queue <int> q;//优先队列;
vector <int> a[100500];//存储点关系的vector;
long long T,n,m,k,ui,vi ,mod=1000000007, ans[100500],ru[200500];//ru记录入度;
bool vis[100500];//记录这个点是否已经被排出;
bool IN[100500];//记录这个点是否在优先队列里;
long long tot,S;//tot就是用来每次加一来向ans里放答案的;
int main()
{
scanf( "%d",&T );
while( T-- )
{
S=0;
tot=0;
scanf("%d%d%d",&n,&m,&k);
memset(vis,0,sizeof(vis));
memset(ru,0,sizeof(ru));
memset(IN,0,sizeof(IN));
for(int i=1;i<=n;i++)
a[i].clear();
//这一堆清零是必须的;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&ui,&vi);
a[ui].push_back(vi);//利用vector连边;
ru[vi]++;//入度加一;
}
for (int i=1;i<=n;i++)
{
q.push(-i);//优先队列是个最大堆,所以把负值存进去就能做到字典序最小啦\(^o^)/~;
IN[i]=1;//现在它在优先队列里;
}
while(!q.empty())//不为空即执行;
{
int now=-q.top();//当前要处理的点;
q.pop();//将它弹出(这个点现在的状态是等待处理);
if( !IN[now] ) continue;//判定无解情况;
IN[now]=0;//现在它不在优先队列里了;
if (ru[now]<=k)//可以删边弹出;
{
vis[now]=1;//现在它被排出来了;
k-=ru[now];//可删边数减少;
ans[++tot]=now;//记录答案;
int len=a[now].size();
for (int j=0;j<len;j++)//扫描其每一个连向的点;
{
int son=a[now][j];//处理儿子;
ru[son]--;//因为它被弹出,现在它的儿子的入度要减一;
if (IN[son]==0 && vis[son]==0)如果它不在优先队列里并且它也没有被排出来(也就是说不满足条件,不是字典序最小也没法排出来);
{
q.push(-son);把它放回去(这一段最好自己模拟一遍就会懂);
IN[son]=1;//现在它又回到优先队列里了;
}
}
}
}
for(int i=1;i<=n;i++)
{
S+=(ans[i]*i)%mod;
S%=mod;
}
printf("%I64d\n",S);
}
return 0;
}