/*
整体思路:有向图的必经边、点 + topo(tarjan)
这放在tarjan的模块里,但实际上可以
用topoDP做,又为了让危险程度最小,
所以我们需要求最短路
然后求必经边的话,是要从S,T分别求
道路方案数的,于是这两个就用topoDP实现
运用Hash的思想,我们选择一个大质数
1e9 + 7,用来模,防止数据过大
然后在最短路上用双指针枚举,求出从
S 到最短路上的第 i 个节点只搭一次车
的最小危险程度ds[],再求出从最短路上第
i 个节点到 T 只搭一次车的最小危险程度
dt[],枚举每个点,用ds[i] + dt[i]更新答案
但是,还有一种情况,我们没有考虑,那就是
将两段乘车的路程连在一起,其实也很好解决
在双指针一次,比最小值就行了
*/
#include <bits/stdc++.h>//万能头
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, M = N * 4, MOD = 1e9 + 7;//MOD用来放置数据过大
int n, m;
int h[N], e[M], ne[M], w[M], idx;//边数组
int p[N], q[N];//队列,与路上倒退用的存边数组
LL din[N][2], f[N][2];//方案数f[][0/1]与入度din[][0/1]0为正向边,1为反向边
LL ds[M], dt[M];//开头注释提到的
LL sum[M], sum_bri[M];//前缀和
bool is_bri[M];//每条边是否为毕竟边
int s, t, Q;
LL dist[N];//最短路
LL a[M], b[M], cnt;
void add(int a, int b, int c)
{
e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx ++ ;//加边
}
void init()
{
memset(h, -1, sizeof h);
memset(ds, 0, sizeof ds);
memset(dt, 0, sizeof dt);
memset(is_bri, 0, sizeof is_bri);//初始化
memset(f, 0, sizeof f);
memset(din, 0, sizeof din);
idx = cnt = 0;
}
void topo(int u, int type)
{
if (!type)
{
memset(dist, 0x3f, sizeof dist);//是否求最短路
dist[u] = 0;
}
int hh = 0, tt = -1;
for (int i = 1; i <= n; i ++ )
if (!din[i][type]) q[ ++ tt] = i;//入队
f[u][type] = 1;//方案数
while (hh <= tt)
{
auto tp = q[hh ++ ];//取出队头
for (int i = h[tp]; ~i; i = ne[i])
{
if ((i & 1) != type) continue;//同向边
int j = e[i];
(f[j][type] += f[tp][type]) %= MOD;//方案数更新
if (!type && dist[j] > dist[tp] + w[i])//最短路
{
dist[j] = dist[tp] + w[i];
p[j] = i;//路径
}
if ( -- din[j][type] == 0) q[ ++ tt] = j;//入队
}
}
}
int main()
{
int T;
cin >> T;
while (T -- )//多组数据
{
init();//初始化
cin >> n >> m >> s >> t >> Q;
s ++ , t ++ ;//节点从1开始
while (m -- )
{
int a, b, c;
cin >> a >> b >> c;
a ++ , b ++ ;
add(a, b, c), add(b, a, c);//加边
din[b][0] ++ ;//正向边入度
din[a][1] ++ ;//反向边入度
}
topo(s, 0);//正向DP
if (!f[t][0])
{
cout << "-1\n";//无法到达
continue;
}
topo(t, 1);//反向DP
for (int i = 0; i < idx; i += 2)
{
int x = e[i ^ 1], y = e[i];
if (f[x][0] * f[y][1] % MOD == f[t][0]) //枚举正向边,记录是否必经
is_bri[i] = is_bri[i ^ 1] = true;
}
int y = t;
while (y != s)
{
a[ ++ cnt] = w[p[y]];
b[cnt] = is_bri[p[y]];
y = e[p[y] ^ 1];//倒推,记录
}
reverse(a + 1, a + 1 + cnt);//翻转
reverse(b + 1, b + 1 + cnt);
for (int i = 1; i <= cnt; i ++ )
{
sum[i] = sum[i - 1] + a[i];
sum_bri[i] = sum_bri[i - 1] + (b[i] ? a[i] : 0);//求前缀
}
for (int i = 1, j = 0; i <= cnt; i ++ )
{
while (sum[i] - sum[j] > Q) j ++ ;
ds[i] = ds[i - 1] + (b[i] ? a[i] : 0);
LL tmp = sum_bri[j];//双指针求ds
if (b[j]) tmp -= Q - sum[i] + sum[j];
ds[i] = min(ds[i], tmp);
}
for (int i = cnt, j = cnt + 1; i; i -- )
{
while (sum[j - 1] - sum[i - 1] > Q) j -- ;
dt[i] = dt[i + 1] + (b[i] ? a[i] : 0);
LL tmp = sum_bri[cnt] - sum_bri[j - 1];//双指针求dt
if(b[j]) tmp -= Q - sum[j - 1] + sum[i - 1];
dt[i] = min(dt[i], tmp);
}
LL res = LLONG_MAX;
for (int i = 1; i <= cnt + 1; i ++ ) res = min(res, dt[i] + ds[i - 1]);//拼
for (int i = 1, j = 0; i <= cnt; i ++ )
{
while (sum[i] - sum[j] > 2 * Q) j ++ ;
LL tmp = sum_bri[j] + sum_bri[cnt] - sum_bri[i];
if (b[j]) tmp -= 2 * Q - sum[i] + sum[j];//双指针处理连续做的情况
res = min(res, tmp);
}
cout << res << '\n';//答案
}
return 0;
}