Problem:
Problem Statement
You want to compete in ICPC (Internet Contest of Point Collection).
In this contest, we move around in $N$ websites, numbered $1$ through $N$, within a time limit and collect points as many as possible.
We can start and end on any website.
There are $M$ links between the websites, and we can move between websites using these links.
You can assume that it doesn't take time to move between websites.
These links are directed and websites may have links to themselves.
In each website $i$, there is an advertisement and we can get $p_i$ point(s) by watching this advertisement in $t_i$ seconds.
When we start on or move into a website, we can decide whether to watch the advertisement or not.
But we cannot watch the same advertisement more than once before using any link in the website, while we can watch it again if we have moved among websites and returned to the website using one or more links, including ones connecting a website to itself.
Also we cannot watch the advertisement in website $i$ more than $k_i$ times.
You want to win this contest by collecting as many points as you can.
So you decided to compute the maximum points that you can collect within $T$ seconds.
Input
The input consists of multiple datasets.
The number of dataset is no more than $60$.
Each dataset is formatted as follows.
$N$ $M$ $T$
$p_1$ $t_1$ $k_1$
:
:
$p_N$ $t_N$ $k_N$
$a_1$ $b_1$
:
:
$a_M$ $b_M$
The first line of each dataset contains three integers $N$ ($1 \le N \le 100$), $M$ ($0 \le M \le 1{,}000$) and $T$ ($1 \le T \le 10{,}000$), which denote the number of websites, the number of links, and the time limit, respectively.
All the time given in the input is expressed in seconds.
The following $N$ lines describe the information of advertisements.
The $i$-th of them contains three integers $p_i$ ($1 \le p_i \le 10{,}000$), $t_i$ ($1 \le t_i \le 10{,}000$) and $k_i$ ($1 \le k_i \le 10{,}000$), which denote the points of the advertisement, the time required to watch the advertisement, and the maximum number of times you can watch the advertisement in website $i$, respectively.
The following $M$ lines describe the information of links.
Each line contains two integers $a_i$ and $b_i$ ($1 \le a_i,b_i \le N$), which mean that we can move from website $a_i$ to website $b_i$ using a link.
The end of input is indicated by a line containing three zeros.
Output
For each dataset, output the maximum points that you can collect within $T$ seconds.
Sample Input
5 4 10
4 3 1
6 4 3
3 2 4
2 2 1
8 5 3
1 2
2 3
3 4
4 5
3 3 1000
1000 1 100
1 7 100
10 9 100
1 2
2 3
3 2
1 0 5
25 25 2
1 0 25
25 25 2
5 5 100
1 1 20
1 1 20
10 1 1
10 1 1
10 1 1
1 2
2 1
3 4
4 5
5 3
3 3 100
70 20 10
50 15 20
90 10 10
1 2
2 2
2 3
0 0 0
Output for the Sample Input
15
2014
0
25
40
390

Submitted solutions:

code_snippet: #pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<queue>
#include<set>
#include<map>
#include<cmath>
#include<ctime>
#include<string.h>
#include<string>
#include<sstream>
#include<bitset>
using namespace std;
#define ll __int64
#define ull unsigned __int64
#define eps 1e-8
#define NMAX 1000000000
#define MOD (1<<30)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define PI acos(-1)
template<class T>
inline void scan_d(T &ret)
{
    char c;
    int flag = 0;
    ret=0;
    while(((c=getchar())<'0'||c>'9')&&c!='-');
    if(c == '-')
    {
        flag = 1;
        c = getchar();
    }
    while(c>='0'&&c<='9') ret=ret*10+(c-'0'),c=getchar();
    if(flag) ret = -ret;
}
const int maxn = 100+10;
const int maxm = 1000+10;
struct Edge
{
    int v,next;
}e[2][maxm];
int head[2][maxn], ecnt[2];
void add_edge(int u, int v, int d)
{
    e[d][ecnt[d]].v = v; e[d][ecnt[d]].next = head[d][u];
    head[d][u] = ecnt[d]++;
}
struct node
{
    int p,t,k;
    node(){}
    node(int _p, int _t, int _k):p(_p),t(_t),k(_k){}
}no[maxn];
bool zi[maxn];

int pre[maxn], lowlink[maxn], sccno[maxn], dfs_clock, scc_cnt, tp;
int S[maxn];
void dfs(int u)
{
    pre[u] = lowlink[u] = ++dfs_clock;
    S[++tp] = u;
    for(int i = head[0][u]; ~i; i = e[0][i].next)
    {
        int v = e[0][i].v;
        if(!pre[v])
        {
            dfs(v);
            lowlink[u] = min(lowlink[u],lowlink[v]);
        }
        else if(!sccno[v]) lowlink[u] = min(lowlink[u],pre[v]);
    }
    if(lowlink[u] == pre[u])
    {
        scc_cnt++;
        while(1)
        {
            int x = S[tp]; tp--;
            sccno[x] = scc_cnt;
            if(x == u) break;
        }
    }
}

void find_scc(int n)
{
    tp = -1;
    dfs_clock = scc_cnt = 0;
    memset(sccno,0,sizeof(sccno));
    memset(pre,0,sizeof(pre));
    for(int i = 1; i <= n; i++) if(!pre[i])
        dfs(i);
}

vector<int>vec[105];

int Em[maxm][2];
bool bian[maxn][maxn];
int in[maxn],top[maxn];
void topo(int n)
{
    queue<int>q;
    for(int i = 1; i <= n; i++) if(in[i] == 0)
        q.push(i);
    int k = 1;
    while(!q.empty())
    {
        int x = q.front(); q.pop();
        top[k++] = x;
        for(int i = head[1][x]; ~i ; i = e[1][i].next)
        {
            int v = e[1][i].v;
            in[v]--;
            if(in[v] == 0) q.push(v);
        }
    }
}
int dp[maxn][10000+10];

node ha[maxn];
int main()
{
#ifdef GLQ
    freopen("input.txt","r",stdin);
//    freopen("o.txt","w",stdout);
#endif
    int n,m,T;
    while(~scanf("%d%d%d",&n,&m,&T) && n+m+T)
    {
        memset(head,-1,sizeof(head));
        memset(ecnt,0,sizeof(ecnt));
        memset(zi,0,sizeof(zi));
        for(int i = 1; i <= n; i++)
            scanf("%d%d%d",&no[i].p,&no[i].t,&no[i].k);
        for(int i = 1; i <= m; i++)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            if(u == v)
            {
                zi[u] = 1;
                Em[i][0] = -1;
            }
            else
            {
                Em[i][0] = u;
                Em[i][1] = v;
                add_edge(u,v,0);
            }
        }
        find_scc(n);
        for(int i = 1; i <= scc_cnt; i++) vec[i].clear();
        for(int i = 1; i <= n; i++)
        {
            vec[sccno[i]].push_back(i);
        }
        for(int i = 1; i <= scc_cnt; i++) if(vec[i].size() == 1 && zi[vec[i][0]] == 0)
            no[vec[i][0]].k = 1;
        memset(bian,0,sizeof(bian));
        memset(in,0,sizeof(in));
        for(int i = 1; i <= m; i++) if(Em[i][0] != -1)
        {
            int u = sccno[Em[i][0]], v = sccno[Em[i][1]];
//            cout<<u<<" "<<v<<endl;
            if(u != v && bian[u][v] == 0)
            {
                bian[u][v] = 1;
                in[v]++;
                add_edge(u,v,1);
            }
        }
        topo(scc_cnt);
        for(int i = 1; i <= scc_cnt; i++)
            for(int j = 0; j <= T; j++)
                dp[i][j] = 0;
        for(int i = 1; i <= scc_cnt; i++)
        {
            int pos = top[i];
            int sz = vec[pos].size();
            for(int j = 0; j < sz; j++)
            {
                int id = vec[pos][j];
                if(no[id].k*no[id].t >= T)
                {
                    for(int v = no[id].t; v <= T; v++)
                        dp[pos][v] = max(dp[pos][v],dp[pos][v-no[id].t]+no[id].p);
                    continue;
                }
                int cnt = 0;
                while((1<<cnt+1)-1 < no[id].k)
                {
                    ha[cnt] = node((1<<cnt)*no[id].p, (1<<cnt)*no[id].t, (1<<cnt));
                    cnt++;
                }
                int tt = no[id].k-(1<<cnt)+1;
                ha[cnt++] = node(tt*no[id].p, tt*no[id].t, tt);
                for(int k = 0; k < cnt; k++)
                {
                    for(int v = T; v >= ha[k].t; v--)
                        dp[pos][v] = max(dp[pos][v],dp[pos][v-ha[k].t]+ha[k].p);
                }
            }
            for(int j = head[1][pos]; ~j; j = e[1][j].next)
            {
                int v = e[1][j].v;
                for(int val = 0; val <= T; val++)
                    dp[v][val] = max(dp[v][val],dp[pos][val]);
            }
        }
        int ans = 0;
        for(int i = 1; i <= scc_cnt; i++)
            ans = max(ans,dp[i][T]);
        printf("%d\n",ans);
    }
    return 0;
}
accuracy: 1
time_ms: 80
memory_kb: 7552
final_rank: 1

code_snippet: // AOJ #2598 Website Tour
// 2025.5.19

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll INF = (ll)-4e18;

int N, M, Tlim;
vector<vector<int>> g, gr;
vector<int> vis, ord, comp;
void dfs1(int u) {
    vis[u] = 1;
    for (int v : g[u]) if (!vis[v]) dfs1(v);
    ord.push_back(u);
}
void dfs2(int u, int cid) {
    comp[u] = cid;
    for (int v : gr[u]) if (comp[v] < 0) dfs2(v, cid);
}

int main(){
    ios::sync_with_stdio(0);
    cin.tie(0);

    while (true) {
        cin >> N >> M >> Tlim;
        if (N==0) break;
        vector<int> p(N), t(N), k(N);
        for (int i = 0; i < N; i++) cin >> p[i] >> t[i] >> k[i];

        g.assign(N, {});
        gr.assign(N, {});
        for (int i = 0, a, b; i < M; i++){
            cin >> a >> b;
            --a; --b;
            g[a].push_back(b);
            gr[b].push_back(a);
        }
        vis.assign(N, 0);
        ord.clear();
        for (int i = 0; i < N; i++) if (!vis[i]) dfs1(i);
        comp.assign(N, -1);
        int C = 0;
        for (int i = N-1; i >= 0; i--){
            int u = ord[i];
            if (comp[u] < 0) dfs2(u, C++);
        }
        vector<int> cyc(C, 0), sz(C, 0);
        for (int i = 0; i < N; i++){
            sz[comp[i]]++;
            for (int v : g[i]){
                if (i == v) cyc[comp[i]] = 1;
                else if (comp[v] == comp[i]) cyc[comp[i]] = 1;
            }
        }
        vector<vector<int>> dag(C);
        vector<int> indeg(C, 0);
        for (int u = 0; u < N; u++){
            for (int v : g[u]){
                int cu = comp[u], cv = comp[v];
                if (cu != cv){
                    dag[cu].push_back(cv);
                }
            }
        }
        for (int i = 0; i < C; i++){
            sort(dag[i].begin(), dag[i].end());
            dag[i].erase(unique(dag[i].begin(), dag[i].end()), dag[i].end());
            for (int j : dag[i]) indeg[j]++;
        }
        vector<vector<pair<int,int>>> it(C);
        for (int i = 0; i < N; i++){
            int ci = comp[i];
            if (!cyc[ci]){
                it[ci].emplace_back(t[i], p[i]);
            } else {
                int cnt = k[i], base = 1;
                while (cnt > 0){
                    int c = min(base, cnt);
                    it[ci].emplace_back(t[i]*c, p[i]*c);
                    cnt -= c;
                    base <<= 1;
                }
            }
        }
        queue<int> q;
        vector<int> topo;
        for (int i = 0; i < C; i++){
            if (indeg[i] == 0) q.push(i);
        }
        while (!q.empty()){
            int u = q.front(); q.pop();
            topo.push_back(u);
            for (int v : dag[u]) if (--indeg[v]==0) q.push(v);
        }
        vector<vector<ll>> dp(C, vector<ll>(Tlim+1, INF));
        for (int c = 0; c < C; c++) dp[c][0] = 0;

        for (int c : topo){
            for (int u = 0; u < C; u++);
            for (int pre = 0; pre < C; pre++);
            for (int t0 = 0; t0 <= Tlim; t0++){
                if (dp[c][t0] < 0 && t0>0) continue;
            }
            for (auto [w, v] : it[c]){
                for (int tt = Tlim; tt >= w; tt--){
                    dp[c][tt] = max(dp[c][tt], dp[c][tt-w] + v);
                }
            }
            for (int nxt : dag[c]){
                for (int tt = 0; tt <= Tlim; tt++){
                    dp[nxt][tt] = max(dp[nxt][tt], dp[c][tt]);
                }
            }
        }
        ll ans = 0;
        for (int c = 0; c < C; c++){
            for (int tt = 0; tt <= Tlim; tt++) ans = max(ans, dp[c][tt]);
        }
        cout << ans << endl;
    }
    return 0;
}
accuracy: 1
time_ms: 120
memory_kb: 11096
final_rank: 11

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define rep(i, n) for (int i = 0; i < (n); i++)
#define rep2(i, n) for (int i = (int)n - 1; i >= 0; i--)
#define REP(i, l, r) for (int i = l; i < (r); i++)
#define REP2(i, l, r) for (int i = (int)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<int> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    int size(int k) {
        return (-data[find(k)]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int operator[](int k) {
        return find(k);
    }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {
    }

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {
    }

    static int get_mod() {
        return mod;
    }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() {
        return *this += Mod_Int(1);
    }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() {
        return *this -= Mod_Int(1);
    }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const {
        return Mod_Int(-x);
    }

    Mod_Int operator+(const Mod_Int &p) const {
        return Mod_Int(*this) += p;
    }

    Mod_Int operator-(const Mod_Int &p) const {
        return Mod_Int(*this) -= p;
    }

    Mod_Int operator*(const Mod_Int &p) const {
        return Mod_Int(*this) *= p;
    }

    Mod_Int operator/(const Mod_Int &p) const {
        return Mod_Int(*this) /= p;
    }

    bool operator==(const Mod_Int &p) const {
        return x == p.x;
    }

    bool operator!=(const Mod_Int &p) const {
        return x != p.x;
    }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1)
                ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    ans %= mod;
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0)
        u += mod;
    return u;
}

ll divide_int(ll a, ll b) {
    return (a >= 0 ? a / b : (a - b + 1) / b);
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    bool rev = n < 0;
    n = abs(n);
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return (rev ? ans.inverse() : ans);
}

// ----- library -------
template <typename T>
vector<T> slide_max(vector<T> v, int k) { // 各 i について min{v[i],v[i+1],...,v[i+k-1]} を記録した配列を返す
    deque<int> que;
    vector<T> ret;
    for (int i = 0; i < (int)v.size(); i++) {
        while (!que.empty() && v[que.back()] <= v[i])
            que.pop_back();
        que.push_back(i);
        if (i - k + 1 >= 0) {
            ret.push_back(v[que.front()]);
            if (que.front() == i - k + 1)
                que.pop_front();
        }
    }
    return ret;
}

// 重さ w, 価値 v で k 個まで入れられる荷物を加える
template <typename T, typename Compare = greater<T>>
vector<T> knapsack(const vector<T> &dp, const int &w, const T &v, const int &k = 1, const Compare &comp = Compare()) {
    int W = dp.size() - 1;
    vector<T> ndp = dp, deqv(W + 1);
    vector<int> deq(W + 1);
    if (w == 0) {
        for (int i = 0; i <= W; i++) {
            if (comp(ndp[i] + v * k, ndp[i]))
                ndp[i] = ndp[i] + v * k;
        }
    } else {
        for (int a = 0; a < w; a++) {
            int s = 0, t = 0;
            for (int i = 0; w * i + a <= W; i++) {
                auto val = ndp[w * i + a] - i * v;
                while (s < t && comp(val, deqv[t - 1]))
                    --t;
                deq[t] = i;
                deqv[t++] = val;
                if (s < t) {
                    ndp[w * i + a] = deqv[s] + v * i;
                    if (deq[s] == i - k)
                        ++s;
                }
            }
        }
    }
    return ndp;
}

using UnWeightedGraph = vector<vector<int>>;

template <typename G>
struct StronglyConnectedComponents {
    const G &g;
    UnWeightedGraph gg, rg;
    vector<int> comp, order, used;

    StronglyConnectedComponents(G &g) : g(g), gg(g.size()), rg(g.size()), comp(g.size(), -1), used(g.size()) {
        for (int i = 0; i < g.size(); i++) {
            for (auto e : g[i]) {
                gg[i].emplace_back((int)e);
                rg[(int)e].emplace_back(i);
            }
        }
    }

    int operator[](int k) {
        return comp[k];
    }

    void dfs(int idx) {
        if (used[idx])
            return;
        used[idx] = true;
        for (int to : gg[idx])
            dfs(to);
        order.push_back(idx);
    }

    void rdfs(int idx, int cnt) {
        if (comp[idx] != -1)
            return;
        comp[idx] = cnt;
        for (int to : rg[idx])
            rdfs(to, cnt);
    }

    void build(UnWeightedGraph &t) {
        for (int i = 0; i < gg.size(); i++)
            dfs(i);
        reverse(begin(order), end(order));
        int ptr = 0;
        for (int i : order)
            if (comp[i] == -1)
                rdfs(i, ptr), ptr++;

        t.resize(ptr);
        for (int i = 0; i < g.size(); i++) {
            for (auto &to : g[i]) {
                int x = comp[i], y = comp[to];
                if (x == y)
                    continue;
                t[x].push_back(y);
            }
        }
    }
};

using SCC = StronglyConnectedComponents<UnWeightedGraph>;
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    while (1) {
        int n, m, lim;
        cin >> n >> m >> lim;
        if (!n)
            break;
        vector<int> p(n), t(n), k(n);
        rep(i, n) cin >> p[i] >> t[i] >> k[i];
        vector<int> a(m), b(m);
        rep(i, m) cin >> a[i] >> b[i], a[i]--, b[i]--;
        UnWeightedGraph g(n), buff;
        rep(i, m) g[a[i]].pb(b[i]);
        SCC scc(g);
        scc.build(buff);
        int sz = buff.size();
        vector<vector<int>> ps(sz);
        vector<int> f(sz, 0);
        rep(i, n) ps[scc[i]].pb(i);
        rep(i, m) if (scc[a[i]] == scc[b[i]]) f[scc[a[i]]] = 1;
        rep(i, n) if (!f[scc[i]]) k[i] = 1;
        vector<vector<int>> li(n);
        rep(i, sz) {
            map<int, bool> m;
            int nsz = ps[i].size();
            rep(j, nsz - 1) li[ps[i][j]].pb(ps[i][j + 1]);
            for (auto e : buff[i]) {
                if (!m[e])
                    li[ps[i][nsz - 1]].pb(ps[e][0]);
                m[e] = true;
            }
        }
        vector<vector<int>> dp0(n, vector<int>(lim + 1, 0)), dp(n, vector<int>(lim + 1, 0));
        vector<int> ord;
        vector<int> d(n, 0);
        rep(i, n) {
            for (auto e : li[i])
                d[e]++;
        }
        queue<int> que;
        rep(i, n) if (!d[i]) que.push(i);
        while (!que.empty()) {
            auto now = que.front();
            que.pop();
            ord.pb(now);
            for (auto e : li[now]) {
                if (!(--d[e]))
                    que.push(e);
            }
        }
        int ans = 0;
        for (auto idx : ord) {
            dp[idx] = knapsack(dp0[idx], t[idx], p[idx], k[idx]);
            rep(i, lim + 1) chmax(ans, dp[idx][i]);
            for (auto e : li[idx]) {
                rep(i, lim + 1) chmax(dp0[e][i], dp[idx][i]);
            }
        }
        cout << ans << '\n';
    }
}
accuracy: 1
time_ms: 170
memory_kb: 11308
final_rank: 14

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define rep(i, n) for (int i = 0; i < (n); i++)
#define rep2(i, n) for (int i = (int)n - 1; i >= 0; i--)
#define REP(i, l, r) for (int i = l; i < (r); i++)
#define REP2(i, l, r) for (int i = (int)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<int> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    int size(int k) {
        return (-data[find(k)]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int operator[](int k) {
        return find(k);
    }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {
    }

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {
    }

    static int get_mod() {
        return mod;
    }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() {
        return *this += Mod_Int(1);
    }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() {
        return *this -= Mod_Int(1);
    }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const {
        return Mod_Int(-x);
    }

    Mod_Int operator+(const Mod_Int &p) const {
        return Mod_Int(*this) += p;
    }

    Mod_Int operator-(const Mod_Int &p) const {
        return Mod_Int(*this) -= p;
    }

    Mod_Int operator*(const Mod_Int &p) const {
        return Mod_Int(*this) *= p;
    }

    Mod_Int operator/(const Mod_Int &p) const {
        return Mod_Int(*this) /= p;
    }

    bool operator==(const Mod_Int &p) const {
        return x == p.x;
    }

    bool operator!=(const Mod_Int &p) const {
        return x != p.x;
    }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1)
                ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    ans %= mod;
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0)
        u += mod;
    return u;
}

ll divide_int(ll a, ll b) {
    return (a >= 0 ? a / b : (a - b + 1) / b);
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    bool rev = n < 0;
    n = abs(n);
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return (rev ? ans.inverse() : ans);
}

// ----- library -------
template <typename T>
vector<T> slide_max(vector<T> v, int k) { // 各 i について min{v[i],v[i+1],...,v[i+k-1]} を記録した配列を返す
    deque<int> que;
    vector<T> ret;
    for (int i = 0; i < (int)v.size(); i++) {
        while (!que.empty() && v[que.back()] <= v[i])
            que.pop_back();
        que.push_back(i);
        if (i - k + 1 >= 0) {
            ret.push_back(v[que.front()]);
            if (que.front() == i - k + 1)
                que.pop_front();
        }
    }
    return ret;
}

// 重さ w, 価値 v で k 個まで入れられる荷物を加える
template <typename T, typename Compare = greater<T>>
vector<T> knapsack(const vector<T> &dp, const int &w, const T &v, const int &k, const Compare &comp = Compare()) {
    int W = dp.size() - 1;
    vector<T> ndp = dp, deqv(W + 1);
    vector<int> deq(W + 1);
    if (w == 0) {
        for (int i = 0; i <= W; i++) {
            if (comp(ndp[i] + v * k, ndp[i]))
                ndp[i] = ndp[i] + v * k;
        }
    } else {
        for (int a = 0; a < w; a++) {
            int s = 0, t = 0;
            for (int i = 0; w * i + a <= W; i++) {
                auto val = ndp[w * i + a] - i * v;
                while (s < t && comp(val, deqv[t - 1]))
                    --t;
                deq[t] = i;
                deqv[t++] = val;
                if (s < t) {
                    ndp[w * i + a] = deqv[s] + v * i;
                    if (deq[s] == i - k)
                        ++s;
                }
            }
        }
    }
    return ndp;
}

using UnWeightedGraph = vector<vector<int>>;

template <typename G>
struct StronglyConnectedComponents {
    const G &g;
    UnWeightedGraph gg, rg;
    vector<int> comp, order, used;

    StronglyConnectedComponents(G &g) : g(g), gg(g.size()), rg(g.size()), comp(g.size(), -1), used(g.size()) {
        for (int i = 0; i < g.size(); i++) {
            for (auto e : g[i]) {
                gg[i].emplace_back((int)e);
                rg[(int)e].emplace_back(i);
            }
        }
    }

    int operator[](int k) {
        return comp[k];
    }

    void dfs(int idx) {
        if (used[idx])
            return;
        used[idx] = true;
        for (int to : gg[idx])
            dfs(to);
        order.push_back(idx);
    }

    void rdfs(int idx, int cnt) {
        if (comp[idx] != -1)
            return;
        comp[idx] = cnt;
        for (int to : rg[idx])
            rdfs(to, cnt);
    }

    void build(UnWeightedGraph &t) {
        for (int i = 0; i < gg.size(); i++)
            dfs(i);
        reverse(begin(order), end(order));
        int ptr = 0;
        for (int i : order)
            if (comp[i] == -1)
                rdfs(i, ptr), ptr++;

        t.resize(ptr);
        for (int i = 0; i < g.size(); i++) {
            for (auto &to : g[i]) {
                int x = comp[i], y = comp[to];
                if (x == y)
                    continue;
                t[x].push_back(y);
            }
        }
    }
};

using SCC = StronglyConnectedComponents<UnWeightedGraph>;
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    while (1) {
        int n, m, lim;
        cin >> n >> m >> lim;
        if (!n)
            break;
        vector<int> p(n), t(n), k(n);
        rep(i, n) cin >> p[i] >> t[i] >> k[i];
        vector<int> a(m), b(m);
        rep(i, m) cin >> a[i] >> b[i], a[i]--, b[i]--;
        UnWeightedGraph g(n), buff;
        rep(i, m) g[a[i]].pb(b[i]);
        SCC scc(g);
        scc.build(buff);
        int sz = buff.size();
        vector<vector<int>> ps(sz);
        vector<int> f(sz, 0);
        rep(i, n) ps[scc[i]].pb(i);
        rep(i, m) if (scc[a[i]] == scc[b[i]]) f[scc[a[i]]] = 1;
        rep(i, n) if (!f[scc[i]]) k[i] = 1;
        vector<vector<int>> li(n);
        rep(i, sz) {
            map<int, bool> m;
            int nsz = ps[i].size();
            rep(j, nsz - 1) li[ps[i][j]].pb(ps[i][j + 1]);
            for (auto e : buff[i]) {
                if (!m[e])
                    li[ps[i][nsz - 1]].pb(ps[e][0]);
                m[e] = true;
            }
        }
        vector<vector<int>> dp0(n, vector<int>(lim + 1, 0)), dp(n, vector<int>(lim + 1, 0));
        vector<int> ord;
        vector<int> d(n, 0);
        rep(i, n) {
            for (auto e : li[i])
                d[e]++;
        }
        queue<int> que;
        rep(i, n) if (!d[i]) que.push(i);
        while (!que.empty()) {
            auto now = que.front();
            que.pop();
            ord.pb(now);
            for (auto e : li[now]) {
                if (!(--d[e]))
                    que.push(e);
            }
        }
        int ans = 0;
        for (auto idx : ord) {
            dp[idx] = knapsack(dp0[idx], t[idx], p[idx], k[idx]);
            rep(i, lim + 1) chmax(ans, dp[idx][i]);
            for (auto e : li[idx]) {
                rep(i, lim + 1) chmax(dp0[e][i], dp[idx][i]);
            }
        }
        cout << ans << '\n';
    }
}
accuracy: 1
time_ms: 170
memory_kb: 11352
final_rank: 15

code_snippet: #pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define pb(...) emplace_back(__VA_ARGS__)
#define mp(a, b) make_pair(a, b)
#define all(x) x.begin(), x.end()
#define rall(x) x.rbegin(), x.rend()
#define rep(i, n) for (int i = 0; i < (n); i++)
#define rep2(i, n) for (int i = (int)n - 1; i >= 0; i--)
#define REP(i, l, r) for (int i = l; i < (r); i++)
#define REP2(i, l, r) for (int i = (int)r - 1; i >= (l); i--)
#define siz(x) (ll) x.size()
template <class T>
using rque = priority_queue<T, vector<T>, greater<T>>;

template <class T>
bool chmin(T &a, const T &b) {
    if (b < a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
bool chmax(T &a, const T &b) {
    if (b > a) {
        a = b;
        return 1;
    }
    return 0;
}

template <class T>
void print(vector<T> a) {
    if (a.empty())
        cout << '\n';
    else {
        for (int i = 0; i < a.size(); i++)
            cout << a[i] << (i + 1 == a.size() ? '\n' : ' ');
    }
}

// __int128_t gcd(__int128_t a, __int128_t b) {
//     if (a == 0)
//         return b;
//     if (b == 0)
//         return a;
//     __int128_t cnt = a % b;
//     while (cnt != 0) {
//         a = b;
//         b = cnt;
//         cnt = a % b;
//     }
//     return b;
// }

long long extGCD(long long a, long long b, long long &x, long long &y) {
    if (b == 0) {
        x = 1;
        y = 0;
        return a;
    }
    long long d = extGCD(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

struct UnionFind {
    vector<int> data;
    int num;

    UnionFind(int sz) {
        data.assign(sz, -1);
        num = sz;
    }

    bool unite(int x, int y) {
        x = find(x), y = find(y);
        if (x == y)
            return (false);
        if (data[x] > data[y])
            swap(x, y);
        data[x] += data[y];
        data[y] = x;
        num--;
        return (true);
    }

    int find(int k) {
        if (data[k] < 0)
            return (k);
        return (data[k] = find(data[k]));
    }

    int size(int k) {
        return (-data[find(k)]);
    }

    bool same(int x, int y) {
        return find(x) == find(y);
    }

    int operator[](int k) {
        return find(k);
    }
};

template <int mod>
struct Mod_Int {
    int x;

    Mod_Int() : x(0) {
    }

    Mod_Int(long long y) : x(y >= 0 ? y % mod : (mod - (-y) % mod) % mod) {
    }

    static int get_mod() {
        return mod;
    }

    Mod_Int &operator+=(const Mod_Int &p) {
        if ((x += p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator-=(const Mod_Int &p) {
        if ((x += mod - p.x) >= mod)
            x -= mod;
        return *this;
    }

    Mod_Int &operator*=(const Mod_Int &p) {
        x = (int)(1LL * x * p.x % mod);
        return *this;
    }

    Mod_Int &operator/=(const Mod_Int &p) {
        *this *= p.inverse();
        return *this;
    }

    Mod_Int &operator++() {
        return *this += Mod_Int(1);
    }

    Mod_Int operator++(int) {
        Mod_Int tmp = *this;
        ++*this;
        return tmp;
    }

    Mod_Int &operator--() {
        return *this -= Mod_Int(1);
    }

    Mod_Int operator--(int) {
        Mod_Int tmp = *this;
        --*this;
        return tmp;
    }

    Mod_Int operator-() const {
        return Mod_Int(-x);
    }

    Mod_Int operator+(const Mod_Int &p) const {
        return Mod_Int(*this) += p;
    }

    Mod_Int operator-(const Mod_Int &p) const {
        return Mod_Int(*this) -= p;
    }

    Mod_Int operator*(const Mod_Int &p) const {
        return Mod_Int(*this) *= p;
    }

    Mod_Int operator/(const Mod_Int &p) const {
        return Mod_Int(*this) /= p;
    }

    bool operator==(const Mod_Int &p) const {
        return x == p.x;
    }

    bool operator!=(const Mod_Int &p) const {
        return x != p.x;
    }

    Mod_Int inverse() const {
        assert(*this != Mod_Int(0));
        return pow(mod - 2);
    }

    Mod_Int pow(long long k) const {
        Mod_Int now = *this, ret = 1;
        for (; k > 0; k >>= 1, now *= now) {
            if (k & 1)
                ret *= now;
        }
        return ret;
    }

    friend ostream &operator<<(ostream &os, const Mod_Int &p) {
        return os << p.x;
    }

    friend istream &operator>>(istream &is, Mod_Int &p) {
        long long a;
        is >> a;
        p = Mod_Int<mod>(a);
        return is;
    }
};

ll mpow2(ll x, ll n, ll mod) {
    ll ans = 1;
    x %= mod;
    while (n != 0) {
        if (n & 1)
            ans = ans * x % mod;
        x = x * x % mod;
        n = n >> 1;
    }
    ans %= mod;
    return ans;
}

ll modinv2(ll a, ll mod) {
    ll b = mod, u = 1, v = 0;
    while (b) {
        ll t = a / b;
        a -= t * b;
        swap(a, b);
        u -= t * v;
        swap(u, v);
    }
    u %= mod;
    if (u < 0)
        u += mod;
    return u;
}

ll divide_int(ll a, ll b) {
    return (a >= 0 ? a / b : (a - b + 1) / b);
}

constexpr int mod = 1000000007;
// constexpr int mod = 998244353;
// constexpr int mod = 31607;
using mint = Mod_Int<mod>;

mint mpow(mint x, ll n) {
    bool rev = n < 0;
    n = abs(n);
    mint ans = 1;
    while (n != 0) {
        if (n & 1)
            ans *= x;
        x *= x;
        n = n >> 1;
    }
    return (rev ? ans.inverse() : ans);
}

// ----- library -------
template <typename T>
vector<T> slide_max(vector<T> v, int k) { // 各 i について min{v[i],v[i+1],...,v[i+k-1]} を記録した配列を返す
    deque<int> que;
    vector<T> ret;
    for (int i = 0; i < (int)v.size(); i++) {
        while (!que.empty() && v[que.back()] <= v[i])
            que.pop_back();
        que.push_back(i);
        if (i - k + 1 >= 0) {
            ret.push_back(v[que.front()]);
            if (que.front() == i - k + 1)
                que.pop_front();
        }
    }
    return ret;
}
using UnWeightedGraph = vector<vector<int>>;

template <typename G>
struct StronglyConnectedComponents {
    const G &g;
    UnWeightedGraph gg, rg;
    vector<int> comp, order, used;

    StronglyConnectedComponents(G &g) : g(g), gg(g.size()), rg(g.size()), comp(g.size(), -1), used(g.size()) {
        for (int i = 0; i < g.size(); i++) {
            for (auto e : g[i]) {
                gg[i].emplace_back((int)e);
                rg[(int)e].emplace_back(i);
            }
        }
    }

    int operator[](int k) {
        return comp[k];
    }

    void dfs(int idx) {
        if (used[idx])
            return;
        used[idx] = true;
        for (int to : gg[idx])
            dfs(to);
        order.push_back(idx);
    }

    void rdfs(int idx, int cnt) {
        if (comp[idx] != -1)
            return;
        comp[idx] = cnt;
        for (int to : rg[idx])
            rdfs(to, cnt);
    }

    void build(UnWeightedGraph &t) {
        for (int i = 0; i < gg.size(); i++)
            dfs(i);
        reverse(begin(order), end(order));
        int ptr = 0;
        for (int i : order)
            if (comp[i] == -1)
                rdfs(i, ptr), ptr++;

        t.resize(ptr);
        for (int i = 0; i < g.size(); i++) {
            for (auto &to : g[i]) {
                int x = comp[i], y = comp[to];
                if (x == y)
                    continue;
                t[x].push_back(y);
            }
        }
    }
};

using SCC = StronglyConnectedComponents<UnWeightedGraph>;
// ----- library -------

int main() {
    ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    cout << fixed << setprecision(15);

    while (1) {
        int n, m, lim;
        cin >> n >> m >> lim;
        if (!n)
            break;
        vector<int> p(n), t(n), k(n);
        rep(i, n) cin >> p[i] >> t[i] >> k[i];
        vector<int> a(m), b(m);
        rep(i, m) cin >> a[i] >> b[i], a[i]--, b[i]--;
        UnWeightedGraph g(n), buff;
        rep(i, m) g[a[i]].pb(b[i]);
        SCC scc(g);
        scc.build(buff);
        int sz = buff.size();
        vector<vector<int>> ps(sz);
        vector<int> f(sz, 0);
        rep(i, n) ps[scc[i]].pb(i);
        rep(i, m) if (scc[a[i]] == scc[b[i]]) f[scc[a[i]]] = 1;
        rep(i, n) if (!f[scc[i]]) k[i] = 1;
        vector<vector<int>> li(n);
        rep(i, sz) {
            map<int, bool> m;
            int nsz = ps[i].size();
            rep(j, nsz - 1) li[ps[i][j]].pb(ps[i][j + 1]);
            for (auto e : buff[i]) {
                if (!m[e])
                    li[ps[i][nsz - 1]].pb(ps[e][0]);
                m[e] = true;
            }
        }
        vector<vector<int>> dp0(n, vector<int>(lim + 1, 0)), dp(n, vector<int>(lim + 1, 0));
        vector<int> ord;
        vector<int> d(n, 0);
        rep(i, n) {
            for (auto e : li[i])
                d[e]++;
        }
        queue<int> que;
        rep(i, n) if (!d[i]) que.push(i);
        while (!que.empty()) {
            auto now = que.front();
            que.pop();
            ord.pb(now);
            for (auto e : li[now]) {
                if (!(--d[e]))
                    que.push(e);
            }
        }
        int ans = 0;
        for (auto idx : ord) {
            dp[idx] = dp0[idx];
            int nsz = (lim + t[idx]) / t[idx];
            chmin(k[idx], nsz);
            rep(x, t[idx]) {
                vector<int> v(nsz);
                rep(i, nsz) if (i * t[idx] + x <= lim) v[i] = dp0[idx][i * t[idx] + x] - p[idx] * i;
                auto res = slide_max(v, k[idx]);
                int ma = 0;
                REP(i, 1, nsz) {
                    if (i * t[idx] + x > lim)
                        break;
                    chmax(ma, v[i - 1]);
                    chmax(dp[idx][i * t[idx] + x], (i >= k[idx] ? res[i - k[idx]] : ma) + p[idx] * i);
                }
            }
            rep(i, lim + 1) chmax(ans, dp[idx][i]);
            for (auto e : li[idx]) {
                rep(i, lim + 1) chmax(dp0[e][i], dp[idx][i]);
            }
        }
        cout << ans << '\n';
    }
}
accuracy: 1
time_ms: 950
memory_kb: 11304
final_rank: 20

code_snippet: #line 1 "g.cpp"
/*	author:  Kite_kuma
	created: 2022.07.02 13:48:51 */

#line 2 "SPJ-Library/graph/graph.hpp"
#include <algorithm>
#include <cassert>
#include <deque>
#include <iostream>
#include <queue>
#include <tuple>
#include <vector>

#pragma region graph

template <class cost_type = long long>
class graph {
   public:
	struct edge {
	   public:
		int from, to;
		cost_type cost;
		int id;
		edge() = default;
		edge(int from_, int to_, cost_type cost_ = 1, int id_ = -1) : from(from_), to(to_), cost(cost_), id(id_) {}
		bool operator<(const edge &a) const { return cost < a.cost; }
		bool operator>(const edge &a) const { return cost > a.cost; }
		friend std::ostream &operator<<(std::ostream &s, const edge &a) {
			s << '(' << a.from << " -> " << a.to << "), cost: " << a.cost << ", id: " << a.id;
			return s;
		}
	};

   private:
	std::vector<std::vector<edge>> edges;
	int next_edge_id = 0;

   public:
	inline const std::vector<edge> &operator[](int k) const { return edges[k]; }
	inline std::vector<edge> &operator[](int k) { return edges[k]; }

	int size() const { return int(edges.size()); }
	void resize(const int n) { edges.resize(n); }
	int edge_count() const { return next_edge_id; }

	friend std::ostream &operator<<(std::ostream &s, const graph<cost_type> &g) {
		for(const auto &adj : g.edges)
			for(const auto &ed : adj) s << ed << '\n';
		return s;
	}

	graph() = default;
	graph(int n) : edges(n) {}
	graph(int n, int e, bool weight = 0, bool directed = 0, int idx = 1) : edges(n) { input(e, weight, directed, idx); }
	const cost_type INF = std::numeric_limits<cost_type>::max() / 3;

	void input(int e = -1, bool weight = false, bool directed = false, int idx = 1) {
		if(e == -1) e = size() - 1;
		while(e--) {
			int u, v;
			std::cin >> u >> v;
			cost_type cost = 1;
			if(weight) std::cin >> cost;
			add_edge(u, v, cost, directed, idx);
		}
	}

	inline int add_edge(int u, int v, cost_type cost = 1, bool directed = false, int idx = 0) {
		u -= idx, v -= idx;
		edges[u].emplace_back(u, v, cost, next_edge_id);
		if(!directed && u != v) edges[v].emplace_back(v, u, cost, next_edge_id);
		return next_edge_id++;
	}

	// Ο(V+E)
	std::vector<cost_type> bfs(int s) const {
		std::vector<cost_type> dist(size(), INF);
		std::queue<int> que;
		dist[s] = 0;
		que.push(s);
		while(!que.empty()) {
			int v = que.front();
			que.pop();
			for(auto &e : edges[v]) {
				if(dist[e.to] != INF) continue;
				dist[e.to] = dist[v] + e.cost;
				que.push(e.to);
			}
		}
		return dist;
	}

	// Ο(V+E)
	// constraint: cost of each edge is zero or x (>= 0)
	std::vector<cost_type> zero_one_bfs(int s) const {
		std::vector<cost_type> dist(size(), INF);
		std::deque<int> deq;
		dist[s] = 0;
		deq.push_back(s);
		while(!deq.empty()) {
			int v = deq.front();
			deq.pop_front();
			for(auto &e : edges[v]) {
				if(dist[e.to] > dist[v] + e.cost) {
					dist[e.to] = dist[v] + e.cost;
					e.cost ? deq.push_back(e.to) : deq.push_front(e.to);
				}
			}
		}
		return dist;
	}

	// Ο((E+V) lg E)
	// unreachable: INF
	std::vector<cost_type> dijkstra(int s) const {
		std::vector<cost_type> dist(size(), INF);
		const auto compare = [](const std::pair<cost_type, int> &a, const std::pair<cost_type, int> &b) {
			return a.first > b.first;
		};
		std::priority_queue<std::pair<cost_type, int>, std::vector<std::pair<cost_type, int>>, decltype(compare)> que{compare};
		dist[s] = 0;
		que.emplace(0, s);
		while(!que.empty()) {
			std::pair<cost_type, int> p = que.top();
			que.pop();
			int v = p.second;
			if(dist[v] < p.first) continue;
			for(auto &e : edges[v]) {
				if(dist[e.to] > dist[v] + e.cost) {
					dist[e.to] = dist[v] + e.cost;
					que.emplace(dist[e.to], e.to);
				}
			}
		}
		return dist;
	}

	// Ο(VE)
	// unreachable: INF
	// reachable via negative cycle: -INF
	std::vector<cost_type> bellman_ford(int s) const {
		int n = size();
		std::vector<cost_type> res(n, INF);
		res[s] = 0;
		for(int loop = 0; loop < n - 1; loop++) {
			for(int v = 0; v < n; v++) {
				if(res[v] == INF) continue;
				for(auto &e : edges[v]) {
					res[e.to] = std::min(res[e.to], res[v] + e.cost);
				}
			}
		}
		std::queue<int> que;
		std::vector<int> chk(n);
		for(int v = 0; v < n; v++) {
			if(res[v] == INF) continue;
			for(auto &e : edges[v]) {
				if(res[e.to] > res[v] + e.cost and !chk[e.to]) {
					que.push(e.to);
					chk[e.to] = 1;
				}
			}
		}
		while(!que.empty()) {
			int now = que.front();
			que.pop();
			for(auto &e : edges[now]) {
				if(!chk[e.to]) {
					chk[e.to] = 1;
					que.push(e.to);
				}
			}
		}
		for(int i = 0; i < n; i++)
			if(chk[i]) res[i] = -INF;
		return res;
	}

	// Ο(V^3)
	std::vector<std::vector<cost_type>> warshall_floyd() const {
		const int n = size();
		std::vector<std::vector<cost_type>> dist(n, std::vector<cost_type>(n, INF));
		for(int i = 0; i < n; i++) dist[i][i] = 0;
		for(int i = 0; i < n; i++)
			for(auto &e : edges[i]) dist[i][e.to] = std::min(dist[i][e.to], e.cost);
		for(int k = 0; k < n; k++)
			for(int i = 0; i < n; i++) {
				if(dist[i][k] == INF) continue;
				for(int j = 0; j < n; j++) {
					if(dist[k][j] == INF) continue;
					dist[i][j] = std::min(dist[i][j], dist[i][k] + dist[k][j]);
				}
			}
		return dist;
	}

	// Ο(V) (using DFS)
	// if a cycle exists, return {}
	std::vector<int> topological_sort() const {
		std::vector<int> res;
		std::vector<int> used(size(), 0);
		bool not_DAG = false;
		auto dfs = [&](auto self, int k) -> void {
			if(not_DAG) return;
			if(used[k]) {
				if(used[k] == 1) not_DAG = true;
				return;
			}
			used[k] = 1;
			for(auto &e : edges[k]) self(self, e.to);
			used[k] = 2;
			res.push_back(k);
		};
		for(int i = 0; i < size(); i++) dfs(dfs, i);
		if(not_DAG) return std::vector<int>{};
		std::reverse(res.begin(), res.end());
		return res;
	}

	bool is_dag() const { return !topological_sort().empty(); }

	// Ο(V)
	// array of the distance to the most distant vertex
	// constraint: the graph is a tree
	std::vector<cost_type> height() const {
		auto vec1 = bfs(0);
		int v1 = -1, v2 = -1;
		cost_type dia = -1;
		for(int i = 0; i < int(size()); i++)
			if(dia < vec1[i]) dia = vec1[i], v1 = i;
		vec1 = bfs(v1);
		dia = -1;
		for(int i = 0; i < int(size()); i++)
			if(dia < vec1[i]) dia = vec1[i], v2 = i;
		auto vec2 = bfs(v2);
		for(int i = 0; i < int(size()); i++) {
			if(vec1[i] < vec2[i]) vec1[i] = vec2[i];
		}
		return vec1;
	}

	// O(V+E)
	// vector<(int)(0 or 1)>
	// if it is not bipartite, return {}
	std::vector<int> bipartite_grouping() const {
		std::vector<int> colors(size(), -1);
		auto dfs = [&](auto self, int now, int col) -> bool {
			colors[now] = col;
			for(auto &e : edges[now]) {
				if(col == colors[e.to]) return false;
				if(colors[e.to] == -1 and !self(self, e.to, !col)) return false;
			}
			return true;
		};
		for(int i = 0; i < int(size()); i++)
			if(colors[i] == -1 and !dfs(dfs, i, 0)) return std::vector<int>{};
		return colors;
	}

	bool is_bipartite() const { return !bipartite_grouping().empty(); }

	// Ο(V+E)
	// (v1, v2, diameter)
	std::tuple<int, int, cost_type> diameter() {
		std::vector<cost_type> dist = bfs(0);
		auto it = std::max_element(dist.begin(), dist.end());
		const int v = it - dist.begin();
		dist = bfs(v);
		it = std::max_element(dist.begin(), dist.end());
		return std::make_tuple(v, int(it - dist.begin()), *it);
	}

	// Ο(V+E)
	std::vector<int> subtree_size(const int root) {
		const int n = size();
		std::vector<int> ret(n, 1);
		auto dfs = [&](auto self, int now, int p = -1) -> void {
			for(const auto &e : (*this)[now]) {
				if(e.to == p) continue;
				self(self, e.to, now);
				ret[now] += ret[e.to];
			}
		};
		dfs(dfs, root);
		return ret;
	}

	// Ο(ElgE)
	cost_type prim() const {
		cost_type res = 0;
		std::priority_queue<edge, std::vector<edge>, std::greater<edge>> que;
		for(auto &e : edges[0]) que.push(e);
		std::vector<int> chk(size());
		chk[0] = 1;
		int cnt = 1;
		while(cnt < size()) {
			auto e = que.top();
			que.pop();
			if(chk[e.to]) continue;
			cnt++;
			res += e.cost;
			chk[e.to] = 1;
			for(auto &e2 : edges[e.to]) que.push(e2);
		}
		return res;
	}

	// Ο(ElgE)
	cost_type kruskal() const {
		std::vector<std::tuple<int, int, cost_type>> eds;
		for(const auto &adj : edges)
			for(const auto &ed : adj) eds.emplace_back(ed.from, ed.to, ed.cost);
		std::sort(eds.begin(), eds.end(), [](const std::tuple<int, int, cost_type> &a, const std::tuple<int, int, cost_type> &b) {
			return std::get<2>(a) < std::get<2>(b);
		});
		std::vector<int> uf_data(size(), -1);
		auto root = [&uf_data](auto self, int x) -> int {
			if(uf_data[x] < 0) return x;
			return uf_data[x] = self(self, uf_data[x]);
		};
		auto unite = [&uf_data, &root](int u, int v) -> bool {
			u = root(root, u), v = root(root, v);
			if(u == v) return false;
			if(uf_data[u] > uf_data[v]) std::swap(u, v);
			uf_data[u] += uf_data[v];
			uf_data[v] = u;
			return true;
		};
		cost_type ret = 0;
		for(auto &e : eds)
			if(unite(std::get<0>(e), std::get<1>(e))) ret += std::get<2>(e);
		return ret;
	}

	// O(V)
	std::vector<int> centroid() const {
		std::vector<int> centroid, sz(size());
		auto dfs = [&](auto self, int now, int per) -> void {
			sz[now] = 1;
			bool is_centroid = true;
			for(auto &e : edges[now]) {
				if(e.to != per) {
					self(self, e.to, now);
					sz[now] += sz[e.to];
					if(sz[e.to] > size() / 2) is_centroid = false;
				}
			}
			if(size() - sz[now] > size() / 2) is_centroid = false;
			if(is_centroid) centroid.push_back(now);
		};
		dfs(dfs, 0, -1);
		return centroid;
	}

	// O(V+E)
	// bridge: (s, t)  (s < t);
	std::pair<std::vector<std::pair<int, int>>, std::vector<int>> bridges_and_articulations() const {
		std::vector<int> order(size(), -1), low(size()), articulation;
		int order_next = 0;
		std::vector<std::pair<int, int>> bridge;
		auto dfs = [&](auto self, int now, int par = -1) -> void {
			low[now] = order[now] = order_next++;
			bool is_articulation = false;
			int cnt = 0;
			for(auto &ed : edges[now]) {
				int &nxt = ed.to;
				if(nxt == par) continue;
				if(order[nxt] == -1) {
					cnt++;
					self(self, nxt, now);
					if(order[now] < low[nxt]) bridge.push_back(std::minmax(now, nxt));
					if(order[now] <= low[nxt]) is_articulation = true;
					low[now] = std::min(low[now], low[nxt]);
				} else if(order[now] > order[nxt]) {
					low[now] = std::min(low[now], order[nxt]);
				}
			}
			if(par == -1 and cnt < 2) is_articulation = false;
			if(is_articulation) articulation.push_back(now);
			return;
		};
		for(int i = 0; i < (int)size(); i++)
			if(order[i] == -1) dfs(dfs, i);
		return std::make_pair(bridge, articulation);
	}

	// Ο(V+E)
	// directed graph from root to leaf
	graph root_to_leaf(int root = 0) const {
		graph res(size());
		std::vector<int> chk(size(), 0);
		chk[root] = 1;
		auto dfs = [&](auto self, int now) -> void {
			for(auto &e : edges[now]) {
				if(chk[e.to] == 1) continue;
				chk[e.to] = 1;
				res.add_edge(now, e.to, e.cost, 1, 0);
				self(self, e.to);
			}
		};
		dfs(dfs, root);
		return res;
	}

	// Ο(V+E)
	// directed graph from leaf to root
	graph leaf_to_root(int root = 0) const {
		graph res(size());
		std::vector<int> chk(size(), 0);
		chk[root] = 1;
		auto dfs = [&](auto self, int now) -> void {
			for(auto &e : edges[now]) {
				if(chk[e.to] == 1) continue;
				chk[e.to] = 1;
				res.add_edge(e.to, now, e.cost, 1, 0);
				self(self, e.to);
			}
		};
		dfs(dfs, root);
		return res;
	}

	// cost_type Chu_Liu_Edmonds(int root = 0) {}
};
#pragma endregion
#line 2 "SPJ-Library/graph/strongly_connected_components.hpp"

template <class cost_type>
struct strongly_connected_components {
   private:
	enum { CHECKED = -1, UNCHECKED = -2 };
	const graph<cost_type> &graph_given;
	graph<int> graph_reversed;
	std::vector<int> order, group_number; /* at the start of the building, 'group_number' is used as 'checked' */
	std::vector<std::vector<int>> groups_;
	graph<int> graph_compressed;

	void dfs(int now) {
		if(group_number[now] != UNCHECKED) return;
		group_number[now] = CHECKED;
		for(const auto &e : graph_given[now]) dfs(e.to);
		order.push_back(now);
	}

	void rdfs(int now, int group_count) {
		if(group_number[now] != UNCHECKED) return;
		group_number[now] = group_count;
		for(const auto &e : graph_reversed[now]) rdfs(e.to, group_count);
	}

	void build(bool create_compressed_graph) {
		for(int i = 0; i < (int)graph_given.size(); i++) dfs(i);
		reverse(order.begin(), order.end());
		group_number.assign(graph_given.size(), UNCHECKED);
		int group = 0;
		for(int i : order)
			if(group_number[i] == UNCHECKED) rdfs(i, group++);
		graph_compressed.resize(group);
		groups_ = std::vector<std::vector<int>>(group);
		for(int i = 0; i < (int)graph_given.size(); i++) groups_[group_number[i]].push_back(i);
		if(create_compressed_graph) {
			std::vector<int> edges(group, -1);
			for(int i = 0; i < group; i++)
				for(int vertex : groups_[i])
					for(const auto &e : graph_given[vertex]) {
						const int dest_group_id = group_number[e.to];
						if(dest_group_id != i && edges[dest_group_id] != i) {
							edges[dest_group_id] = i;
							graph_compressed.add_edge(i, dest_group_id, 1, true, 0);
						}
					}
		}
		return;
	}

   public:
	strongly_connected_components(const graph<cost_type> &g, bool create_compressed_graph = true)
		: graph_given(g), graph_reversed(g.size()), group_number(g.size(), UNCHECKED) {
		for(int i = 0; i < g.size(); i++)
			for(const auto &e : graph_given[i]) graph_reversed.add_edge(e.to, e.from, 1, true, 0);
		build(create_compressed_graph);
	}

	const int &operator[](const int k) const { return group_number[k]; }

	std::vector<std::vector<int>> groups() const { return groups_; }

	graph<int> compressed_graph() const { return graph_compressed; }
};
#line 2 "SPJ-Library/template/kuma.hpp"

#line 2 "SPJ-Library/template/basic_func.hpp"

#line 7 "SPJ-Library/template/basic_func.hpp"

template <class T0, class T1, class T2>
inline bool in_range(T0 x, T1 lef, T2 rig) {
	return ((lef <= x) && (x < rig));
}

template <class T>
inline bool chmin(T &a, T b) {
	if(a > b) {
		a = b;
		return true;
	}
	return false;
}
template <class T>
inline bool chmax(T &a, T b) {
	if(a < b) {
		a = b;
		return true;
	}
	return false;
}

void Yes(bool flag = true) { std::cout << (flag ? "Yes" : "No") << '\n'; }
void YES(bool flag = true) { std::cout << (flag ? "YES" : "NO") << '\n'; }

template <class T>
void drop(T answer) {
	std::cout << answer << '\n';
	exit(0);
}

template <class T>
void vout(std::vector<T> const &v, bool vertically = 0) {
	if(vertically) {
		for(auto const &a : v) {
			std::cout << a << '\n';
		}
		return;
	}
	for(auto it = v.begin(); it != v.end(); it++) {
		std::cout << (*it);
		if(it != v.end() - 1) {
			std::cout << ' ';
		}
	}
	std::cout << '\n';
	return;
}

inline void print() { std::cout << '\n'; }
template <class T>
inline void print(const T &x) {
	std::cout << x << '\n';
	return;
}
template <typename Head, typename... Tail>
void print(const Head &H, const Tail &... T) {
	std::cout << H << " ";
	print(T...);
}

template <class T>
void add(std::vector<T> &v, T value) {
	for(auto &a : v) a += value;
	return;
}

template <class T>
T greatest_lower_multiple(T x, T d) {
	if(d == 0) return 0;
	if(d < 0) d *= -1;
	T y = x % d;
	if(y < 0) y += d;
	return x - y;
}

template <class T>
T least_upper_multiple(T x, T d) {
	return -greatest_lower_multiple(-x, d);
}

// ceil(a / b);
template <class T>
T dup(T a, T b) {
	assert(b);
	if(b < 0) {
		a *= -1;
		b *= -1;
	}
	return least_upper_multiple(a, b) / b;
}

long long pow_ll(long long a, long long n) {
	assert(n >= 0LL);
	if(n == 0) return 1LL;
	if(a == 0) return 0LL;
	if(a == 1) return 1LL;
	if(a == -1) return (n & 1LL) ? -1LL : 1LL;
	long long res = 1;
	while(n > 1LL) {
		if(n & 1LL) res *= a;
		a *= a;
		n >>= 1;
	}
	return res * a;
}

long long modpow(long long a, long long n, long long mod) {	 // a^n mod
	assert(n >= 0 && mod);
	if(mod == 1) return 0LL;
	long long res = 1;
	a %= mod;
	while(n > 0) {
		if(n & 1) res = res * a % mod;
		a = a * a % mod;
		n >>= 1;
	}
	return res < 0 ? res + mod : res;
}

// return x which satisfies a * x % mod == gcd(a, mod)
// not (mod | a)
long long modinv(long long a, const long long mod) {
	long long b = mod, u = 1, v = 0;
	while(b) {
		long long t = a / b;
		a -= t * b;
		std::swap(a, b);
		u -= t * v;
		std::swap(u, v);
	}
	u %= mod;
	if(u < 0) u += mod;
	return u;
}

template <class T>
int lb(const std::vector<T> &a, const T x) {
	return (int)std::distance(a.begin(), std::lower_bound(a.begin(), a.end(), x));
}
template <class T>
int ub(const std::vector<T> &a, const T x) {
	return (int)std::distance(a.begin(), std::upper_bound(a.begin(), a.end(), x));
}
template <class T>
void unq_sort(std::vector<T> &a) {
	std::sort(a.begin(), a.end());
	a.erase(std::unique(a.begin(), a.end()), a.end());
}
template <class T>
std::vector<int> press(const std::vector<T> &a) {
	std::vector<T> vec = a;
	unq_sort(vec);
	std::vector<int> ret;
	for(const auto &v : a) ret.push_back(lb(vec, v));
	return ret;
}
#line 1 "SPJ-Library/template/header.hpp"
#include <bits/stdc++.h>
#line 2 "SPJ-Library/template/io.hpp"

#line 4 "SPJ-Library/template/io.hpp"

#line 8 "SPJ-Library/template/debug.hpp"

#line 3 "SPJ-Library/template/constants.hpp"

constexpr int inf = 1000'000'000;
constexpr long long INF = 1'000'000'000'000'000'000LL;
constexpr int mod_1000000007 = 1000000007;
constexpr int mod_998244353 = 998244353;
const long double pi = acosl(-1.);
constexpr int dx[8] = {1, 0, -1, 0, 1, -1, -1, 1};
constexpr int dy[8] = {0, 1, 0, -1, 1, 1, -1, -1};
#line 10 "SPJ-Library/template/debug.hpp"

namespace viewer {

template <typename T, typename U>
void view(const std::pair<T, U> &p);

template <class T0, class T1, class T2>
void view(const std::tuple<T0, T1, T2> &p);

template <class T0, class T1, class T2, class T3>
void view(const std::tuple<T0, T1, T2, T3> &p);

void view(const long long &e);

void view(const int &e);

template <typename T>
void view(const T &e);

template <typename T>
void view(const std::set<T> &s);

template <typename T>
void view(const std::unordered_set<T> &s);

template <typename T>
void view(const std::multiset<T> &s);

template <typename T>
void view(const std::unordered_multiset<T> &s);

template <typename T>
void view(const std::vector<T> &v);

template <typename T, std::size_t ary_size>
void view(const std::array<T, ary_size> &v);

template <typename T>
void view(const std::vector<std::vector<T>> &vv);

template <typename T, typename U>
void view(const std::vector<std::pair<T, U>> &v);

template <class T0, class T1, class T2>
void view(const std::vector<std::tuple<T0, T1, T2>> &v);

template <class T0, class T1, class T2, class T3>
void view(const std::vector<std::tuple<T0, T1, T2, T3>> &v);

template <typename map_type>
void view_map_container(const map_type &m);

template <typename T, typename U>
void view(const std::map<T, U> &m);

template <typename T, typename U>
void view(const std::unordered_map<T, U> &m);

template <typename container_type>
void view_container(const container_type &c, bool vertically = false) {
	typename container_type::const_iterator begin = c.begin();
	const typename container_type::const_iterator end = c.end();
	if(vertically) {
		std::cerr << "{\n";
		while(begin != end) {
			std::cerr << '\t';
			view(*(begin++));
			if(begin != end) std::cerr << ',';
			std::cerr << '\n';
		}
		std::cerr << '}';
		return;
	}
	std::cerr << "{ ";
	while(begin != end) {
		view(*(begin++));
		if(begin != end) std::cerr << ',';
		std::cerr << ' ';
	}
	std::cerr << '}';
}

template <typename T, typename U>
void view(const std::pair<T, U> &p) {
	std::cerr << '(';
	view(p.first);
	std::cerr << ", ";
	view(p.second);
	std::cerr << ')';
}

template <class T0, class T1, class T2>
void view(const std::tuple<T0, T1, T2> &p) {
	std::cerr << '(';
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ')';
}

template <class T0, class T1, class T2, class T3>
void view(const std::tuple<T0, T1, T2, T3> &p) {
	std::cerr << '(';
	view(std::get<0>(p));
	std::cerr << ", ";
	view(std::get<1>(p));
	std::cerr << ", ";
	view(std::get<2>(p));
	std::cerr << ", ";
	view(std::get<3>(p));
	std::cerr << ')';
}

void view(const long long &e) {
	if(e == INF)
		std::cerr << "INF";
	else if(e == -INF)
		std::cerr << "-INF";
	else
		std::cerr << e;
}

void view(const int &e) {
	if(e == inf)
		std::cerr << "inf";
	else if(e == -inf)
		std::cerr << "-inf";
	else
		std::cerr << e;
}

template <typename T>
void view(const T &e) {
	std::cerr << e;
}

template <typename T>
void view(const std::set<T> &s) {
	view_container(s);
}

template <typename T>
void view(const std::unordered_set<T> &s) {
	view_container(s);
}

template <typename T>
void view(const std::multiset<T> &s) {
	view_container(s);
}

template <typename T>
void view(const std::unordered_multiset<T> &s) {
	view_container(s);
}

template <typename T>
void view(const std::vector<T> &v) {
	view_container(v);
}

template <typename T, std::size_t ary_size>
void view(const std::array<T, ary_size> &v) {
	view_container(v);
}

template <typename T>
void view(const std::vector<std::vector<T>> &vv) {
	view_container(vv, true);
}

template <typename T, typename U>
void view(const std::vector<std::pair<T, U>> &v) {
	view_container(v, true);
}

template <class T0, class T1, class T2>
void view(const std::vector<std::tuple<T0, T1, T2>> &v) {
	view_container(v, true);
}

template <class T0, class T1, class T2, class T3>
void view(const std::vector<std::tuple<T0, T1, T2, T3>> &v) {
	view_container(v, true);
}

template <typename map_type>
void view_map_container(const map_type &m) {
	std::cerr << "{\n";
	for(typename map_type::const_iterator it = m.begin(); it != m.end(); it++) {
		std::cerr << "\t[";
		view(it->first);
		std::cerr << "] : ";
		view(it->second);
		std::cerr << '\n';
	}
	std::cerr << "}";
}

template <typename T, typename U>
void view(const std::map<T, U> &m) {
	view_map_container(m);
}

template <typename T, typename U>
void view(const std::unordered_map<T, U> &m) {
	view_map_container(m);
}

}  // namespace viewer

// when compiling : g++ foo.cpp -DLOCAL
#ifdef LOCAL
void debug_out() {}
template <typename T>
void debug_out(const T &x) {
	viewer::view(x);
}
template <typename Head, typename... Tail>
void debug_out(const Head &H, const Tail &... T) {
	viewer::view(H);
	std::cerr << ", ";
	debug_out(T...);
}
#define debug(...)                                                \
	do {                                                          \
		std::cerr << __LINE__ << " [" << #__VA_ARGS__ << "] : ["; \
		debug_out(__VA_ARGS__);                                   \
		std::cerr << "]\n";                                       \
	} while(0)
#else
#define debug(...) (void(0))
#endif
#line 2 "SPJ-Library/template/scanner.hpp"

#line 6 "SPJ-Library/template/scanner.hpp"

namespace scanner {
template <class T>
void scan(T &a) {
	std::cin >> a;
}

template <class T, class L>
void scan(std::pair<T, L> &p) {
	scan(p.first);
	scan(p.second);
}

template <class T0, class T1, class T2>
void scan(std::tuple<T0, T1, T2> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	scan(t0);
	scan(t1);
	scan(t2);
	p = std::make_tuple(t0, t1, t2);
}

template <class T0, class T1, class T2, class T3>
void scan(std::tuple<T0, T1, T2, T3> &p) {
	T0 t0;
	T1 t1;
	T2 t2;
	T3 t3;
	scan(t0);
	scan(t1);
	scan(t2);
	scan(t3);
	p = std::make_tuple(t0, t1, t2, t3);
}

template <class T>
void scan(std::vector<T> &a) {
	for(auto &i : a) scan(i);
}

void INPUT() {}
template <class Head, class... Tail>
void INPUT(Head &head, Tail &... tail) {
	scan(head);
	INPUT(tail...);
}
}  // namespace scanner
#line 7 "SPJ-Library/template/io.hpp"

#define VEC(type, name, size) \
	vector<type> name(size);  \
	scanner::INPUT(name)
#define VVEC(type, name, h, w)                     \
	vector<vector<type>> name(h, vector<type>(w)); \
	scanner::INPUT(name)
#define INT(...)     \
	int __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LL(...)            \
	long long __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define STR(...)        \
	string __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define CHR(...)      \
	char __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define DBL(...)        \
	double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define LD(...)              \
	long double __VA_ARGS__; \
	scanner::INPUT(__VA_ARGS__)
#define TPL3(type0, type1, type2, name)   \
	std::tuple<type0, type1, type2> name; \
	scanner::INPUT(name);
#define TPL4(type0, type1, type2, type3, name)   \
	std::tuple<type0, type1, type2, type3> name; \
	scanner::INPUT(name);

template <typename T1, typename T2>
std::istream &operator>>(std::istream &is, std::pair<T1, T2> &p) {
	is >> p.first >> p.second;
	return is;
}

template <typename T1, typename T2>
std::ostream &std::operator<<(std::ostream &os, const std::pair<T1, T2> &p) {
	os << p.first << ' ' << p.second;
	return os;
}
template <class T>
std::ostream &std::operator<<(std::ostream &os, const std::vector<T> &v) {
	for(typename std::vector<T>::const_iterator it = v.begin(); it != v.end(); it++) {
		if(it != v.begin()) std::cerr << ' ';
		os << *it;
	}
	return os;
}

struct fast_io {
	fast_io() {
		std::ios::sync_with_stdio(false);
		std::cin.tie(nullptr);
		std::cout << std::fixed << std::setprecision(15);
		srand((unsigned)time(NULL));
	}
} fast_io_;
#line 2 "SPJ-Library/template/macros.hpp"

#define foa(s, v) for(auto &s : v)
#define all(v) (v).begin(), (v).end()
#define rall(v) (v).rbegin(), (v).rend()
#define pcnt(n) __builtin_popcountll((long long)n)

#define REPname(a, b, c, d, e, ...) e
#define rep(...) REPname(__VA_ARGS__, REP3, REP2, REP1, REP0)(__VA_ARGS__)
#define REP0(x) for(int Counter_in_rep_macro = 0; Counter_in_rep_macro < (x); ++Counter_in_rep_macro)
#define REP1(i, x) for(int i = 0; i < (x); ++i)
#define REP2(i, l, r) for(int i = (l); i < (r); ++i)
#define REP3(i, l, r, c) for(int i = (l); i < (r); i += (c))
#define DREPname(a, b, c, d, e, ...) e
#define drep(...) DREPname(__VA_ARGS__, DREP3, DREP2, DREP1)(__VA_ARGS__)
#define DREP1(i, x) for(int i = (x)-1; i >= 0; --i)
#define DREP2(i, l, r) for(int i = (r)-1; i >= (l); --i)
#define DREP3(i, l, r, c) for(int i = (r)-1; i >= (l); i -= (c))

using ll = long long;
using ld = long double;
using ull = unsigned long long;
using vi = std::vector<int>;
using vvi = std::vector<std::vector<int>>;
using vvvi = std::vector<std::vector<std::vector<int>>>;
using vll = std::vector<ll>;
using vvll = std::vector<vll>;
using vvvll = std::vector<vvll>;
template <class T = ll>
using V = std::vector<T>;
template <class T = ll>
using VV = V<V<T>>;
template <class T = ll>
using VVV = V<V<V<T>>>;
template <class T = ll>
using pqup = std::priority_queue<T, std::vector<T>, std::greater<T>>;
template <class T = ll>
using pqdn = std::priority_queue<T>;
#line 7 "SPJ-Library/template/kuma.hpp"

using namespace std;
#line 6 "g.cpp"

// vector<ll> knapsack(vector<ll> table /* 前計算した長さ T のテーブル */, vector<ll> value, vector<int> weight, vector<int> cnt);
vector<ll> knapsack(vector<ll> table, vector<ll> v, vector<int> w, vector<int> c) {
	int n = v.size();
	vector<ll> nv, nw;
	rep(i, n) {
		rep(j, 15) {
			int sz = (1 << j);
			if(c[i] >= sz) {
				c[i] -= sz;
				nv.push_back(v[i] * sz);
				nw.push_back(w[i] * sz);
			}
		}
		if(c[i]) {
			nv.push_back(v[i] * c[i]);
			nw.push_back(w[i] * c[i]);
		}
	}
	n = nv.size();
	rep(i, n) {
		drep(j, int(table.size())) {
			if(j - nw[i] >= 0) chmax(table[j], table[j - nw[i]] + nv[i]);
		}
	}
	return table;
}

void solve(int n) {
	int m;
	cin >> m;
	int time_max;
	cin >> time_max;
	vector<ll> value(n);
	vector<int> time(n), upper(n);
	rep(i, n) cin >> value[i] >> time[i] >> upper[i];

	graph<int> g(n, m, false, true);
	strongly_connected_components<int> scc(g);

	auto gps = scc.groups();
	auto cg = scc.compressed_graph();

	int vs = cg.size();
	vector<vector<ll>> tables(vs, vll(time_max + 1, 0));

	vi selfloop(n);
	rep(i, n) foa(e, g[i]) {
		if(e.to == i) {
			selfloop[i] = 1;
		}
	}

	rep(i, vs) {
		vll value_i;
		vi weight_i, count_i;
		foa(v, gps[i]) {
			value_i.push_back(value[v]);
			weight_i.push_back(time[v]);
			count_i.push_back(upper[v]);
		}
		if(gps[i].size() == 1 && selfloop[gps[i].front()] == 0) {
			count_i.back() = 1;
		}
		tables[i] = knapsack(tables[i], value_i, weight_i, count_i);
		foa(e, cg[i]) {
			rep(t, time_max) { chmax(tables[e.to][t], tables[i][t]); }
		}
	}

	ll ans = 0;
	foa(v, tables) {
		foa(c, v) { chmax(ans, c); }
	}

	print(ans);
	return;
}

int main() {
	int n;
	while(cin >> n && n) {
		solve(n);
	}
}
accuracy: 1
time_ms: 230
memory_kb: 11280
final_rank: 16

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=105,INF=1<<30;

int V,cmp[MAX];
vector<int> G[MAX],rG[MAX],vs;//vsがトポソの逆順になってる
bool used[MAX];

void add_edge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}

void add_clause(int i,bool f,int j,bool g){
    add_edge(2*i+(!f),2*j+g);
    add_edge(2*j+(!g),2*i+f);
}

void DFS(int v){
    used[v]=1;
    for(int i=0;i<G[v].size();i++){
        if(used[G[v][i]]==0) DFS(G[v][i]);
    }
    vs.push_back(v);
}

void rDFS(int v,int k){
    used[v]=1;
    cmp[v]=k;
    for(int i=0;i<rG[v].size();i++){
        if(used[rG[v][i]]==0) rDFS(rG[v][i],k);
    }
}

int scc(){
    memset(used,0,sizeof(used));
    vs.clear();
    for(int v=0;v<V;v++){
        if(used[v]==0) DFS(v);
    }
    
    memset(used,0,sizeof(used));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
        if(used[vs[i]]==0) rDFS(vs[i],k++);
    }
    return k;
}

vector<int> from[MAX],ro[MAX];

int dp[MAX][20005];

void init(int N){
    V=N;
    for(int i=0;i<N;i++){
        G[i].clear();
        rG[i].clear();
        from[i].clear();
        cmp[i]=used[i]=false;
        ro[i].clear();
        for(int j=0;j<=20000;j++) dp[i][j]=0;
    }
    vs.clear();
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N,M,T;cin>>N>>M>>T;
        if(N==0) break;
        init(N);
        vector<int> v(N),w(N),lim(N),roop(N);
        for(int i=0;i<N;i++) cin>>v[i]>>w[i]>>lim[i];
        for(int i=0;i<M;i++){
            int a,b;cin>>a>>b;
            a--;b--;
            add_edge(a,b);
            if(a==b) roop[a]=true;
        }
        int K=scc();
        set<pair<int,int>> SE;
        for(int i=0;i<N;i++){
            for(int to:G[i]){
                if(cmp[i]!=cmp[to]) SE.insert(mp(cmp[i],cmp[to]));
            }
            ro[cmp[i]].push_back(i);
        }
        
        for(auto e:SE){
            from[e.se].push_back(e.fi);
        }
        
        for(int i=0;i<K;i++){
            vector<int> pre(T+1);
            for(int p:from[i]){
                for(int j=0;j<=T;j++){
                    chmax(pre[j],dp[p][j]);
                }
            }
            if(si(ro[i])>=2||roop[ro[i][0]]){
                for(int u:ro[i]){
                    for(int a=0;a<w[u];a++){
                        deque<int> deq,deqv;
                        for(int j=0;j*w[u]+a<=T;j++){
                            int val=pre[j*w[u]+a]-j*v[u];
                            while(si(deq)&&deqv.back()<=val){
                                deq.pop_back();
                                deqv.pop_back();
                            }
                            deq.push_back(j);
                            deqv.push_back(val);
                            pre[j*w[u]+a]=deqv.front()+j*v[u];
                            if(deq.front()==j-lim[u]){
                                deq.pop_front();
                                deqv.pop_front();
                            }
                        }
                    }
                }
            }else{
                for(int j=T;j>=w[ro[i][0]];j--) chmax(pre[j],pre[j-w[ro[i][0]]]+v[ro[i][0]]);
            }
            
            for(int j=0;j<=T;j++) dp[i][j]=pre[j];
            
        }
        
        int ans=0;
        
        for(int i=0;i<K;i++){
            for(int j=0;j<=T;j++){
                chmax(ans,dp[i][j]);
            }
        }
        
        cout<<ans<<"\n";
        
    }
}
accuracy: 1
time_ms: 650
memory_kb: 11644
final_rank: 18

code_snippet: #include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=105,INF=1<<30;

int V,cmp[MAX];
vector<int> G[MAX],rG[MAX],vs;//vsがトポソの逆順になってる
bool used[MAX];

void add_edge(int from,int to){
    G[from].push_back(to);
    rG[to].push_back(from);
}

void add_clause(int i,bool f,int j,bool g){
    add_edge(2*i+(!f),2*j+g);
    add_edge(2*j+(!g),2*i+f);
}

void DFS(int v){
    used[v]=1;
    for(int i=0;i<G[v].size();i++){
        if(used[G[v][i]]==0) DFS(G[v][i]);
    }
    vs.push_back(v);
}

void rDFS(int v,int k){
    used[v]=1;
    cmp[v]=k;
    for(int i=0;i<rG[v].size();i++){
        if(used[rG[v][i]]==0) rDFS(rG[v][i],k);
    }
}

int scc(){
    memset(used,0,sizeof(used));
    vs.clear();
    for(int v=0;v<V;v++){
        if(used[v]==0) DFS(v);
    }
    
    memset(used,0,sizeof(used));
    int k=0;
    for(int i=vs.size()-1;i>=0;i--){
        if(used[vs[i]]==0) rDFS(vs[i],k++);
    }
    return k;
}

vector<int> fro[MAX],ro[MAX];

int dp[MAX][20005];

void init(int N){
    V=N;
    for(int i=0;i<N;i++){
        G[i].clear();
        rG[i].clear();
        fro[i].clear();
        cmp[i]=used[i]=false;
        ro[i].clear();
        for(int j=0;j<=20000;j++) dp[i][j]=0;
    }
    vs.clear();
}

int main(){
    
    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);
    
    while(1){
        int N,M,T;cin>>N>>M>>T;
        if(N==0) break;
        init(N);
        vector<int> v(N),w(N),lim(N),roop(N);
        for(int i=0;i<N;i++) cin>>v[i]>>w[i]>>lim[i];
        for(int i=0;i<M;i++){
            int a,b;cin>>a>>b;
            a--;b--;
            add_edge(a,b);
            if(a==b) roop[a]=true;
        }
        int K=scc();
        set<pair<int,int>> SE;
        for(int i=0;i<N;i++){
            for(int to:G[i]){
                if(cmp[i]!=cmp[to]) SE.insert(mp(cmp[i],cmp[to]));
            }
            ro[cmp[i]].push_back(i);
        }
        
        for(auto e:SE){
            fro[e.se].push_back(e.fi);
        }
        
        for(int i=0;i<K;i++){
            vector<int> pre(T+1);
            for(int p:fro[i]){
                for(int j=0;j<=T;j++){
                    chmax(pre[j],dp[p][j]);
                }
            }
            if(si(ro[i])>=2||roop[ro[i][0]]){
                for(int u:ro[i]){
                    for(int a=0;a<w[u];a++){
                        deque<int> deq,deqv;
                        for(int j=0;j*w[u]+a<=T;j++){
                            int val=pre[j*w[u]+a]-j*v[u];
                            while(si(deq)&&deqv.back()<=val){
                                deq.pop_back();
                                deqv.pop_back();
                            }
                            deq.push_back(j);
                            deqv.push_back(val);
                            pre[j*w[u]+a]=deqv.front()+j*v[u];
                            if(deq.front()==j-lim[u]){
                                deq.pop_front();
                                deqv.pop_front();
                            }
                        }
                    }
                }
            }else{
                for(int j=T;j>=w[ro[i][0]];j--) chmax(pre[j],pre[j-w[ro[i][0]]]+v[ro[i][0]]);
            }
            
            for(int j=0;j<=T;j++) dp[i][j]=pre[j];
            
        }
        
        int ans=0;
        
        for(int i=0;i<K;i++){
            for(int j=0;j<=T;j++){
                chmax(ans,dp[i][j]);
            }
        }
        
        cout<<ans<<"\n";
        
    }
}
accuracy: 1
time_ms: 650
memory_kb: 11736
final_rank: 19

code_snippet: #include <bits/stdc++.h>
using namespace std;
struct strongly_connected_components{
  int cnt;
  vector<int> scc;
  void dfs(vector<vector<int>> &E, vector<bool> &used, vector<int> &in, int v){
    for (int w : E[v]){
      if (!used[w]){
        used[w] = true;
        dfs(E, used, in, w);
      }
    }
    in.push_back(v);
  }
  strongly_connected_components(vector<vector<int>> &E){
    int N = E.size();
    vector<vector<int>> E2(N);
    for (int i = 0; i < N; i++){
      for (int j : E[i]){
        E2[j].push_back(i);
      }
    }
    vector<bool> used(N, false);
    vector<int> in;
    for (int i = 0; i < N; i++){
      if (!used[i]){
        used[i] = true;
        dfs(E, used, in, i);
      }
    }
    cnt = 0;
    scc = vector<int>(N, -1);
    for (int i = N - 1; i >= 0; i--){
      if (scc[in[i]] == -1){
        scc[in[i]] = cnt;
        queue<int> Q;
        Q.push(in[i]);
        while (!Q.empty()){
          int v = Q.front();
          Q.pop();
          for (int w : E2[v]){
            if (scc[w] == -1){
              scc[w] = cnt;
              Q.push(w);
            }
          }
        }
        cnt++;
      }
    }
  }
  int operator [](int k){
    return scc[k];
  }
};
int main(){
  while (true){
    int N, M, T;
    cin >> N >> M >> T;
    if (N == 0 && M == 0 && T == 0){
      break;
    }
    vector<int> p(N), t(N), k(N);
    for (int i = 0; i < N; i++){
      cin >> p[i] >> t[i] >> k[i];
    }
    vector<vector<int>> E(N);
    for (int i = 0; i < M; i++){
      int a, b;
      cin >> a >> b;
      a--;
      b--;
      E[a].push_back(b);
    }
    strongly_connected_components G(E);
    int cnt = G.cnt;
    vector<vector<int>> id(cnt);
    for (int i = 0; i < N; i++){
      id[G[i]].push_back(i);
    }
    vector<bool> e(cnt, false);
    vector<vector<int>> E2(cnt);
    for (int i = 0; i < N; i++){
      for (int j : E[i]){
        if (G[i] == G[j]){
          e[G[i]] = true;
        } else {
          E2[G[i]].push_back(G[j]);
        }
      }
    }
    for (int i = 0; i < cnt; i++){
      if (!e[i]){
        k[id[i][0]] = 1;
      }
    }
    vector<vector<int>> nxt(N);
    for (int i = 0; i < cnt; i++){
      int sz = id[i].size();
      for (int j = 0; j < sz - 1; j++){
        nxt[id[i][j]].push_back(id[i][j + 1]);
      }
      for (int j : E2[i]){
        nxt[id[i][sz - 1]].push_back(id[j][0]);
      }
    }
    vector<int> in;
    for (int i = 0; i < cnt; i++){
      int sz = id[i].size();
      for (int j = 0; j < sz; j++){
        in.push_back(id[i][j]);
      }
    }
    vector<vector<int>> dp(N, vector<int>(T + 1, 0));
    for (int i = 0; i < N; i++){
      for (int j = 0; j < t[in[i]]; j++){
        deque<pair<int, int>> dq;
        for (int l = 0; l * t[in[i]] + j <= T; l++){
          int x = dp[in[i]][l * t[in[i]] + j] - l * p[in[i]];
          while (!dq.empty()){ 
            if (dq.back().second <= x){
              dq.pop_back();
            } else {
              break;
            }
          }
          dq.push_back(make_pair(l, x));
          dp[in[i]][l * t[in[i]] + j] = dq.front().second + l * p[in[i]];
          if (dq.front().first == l - k[in[i]]){
            dq.pop_front();
          }
        }
      }
      for (int j : nxt[in[i]]){
        for (int l = 0; l <= T; l++){
          dp[j][l] = max(dp[j][l], dp[in[i]][l]);
        }
      }
    }
    int ans = 0;
    for (int i = 0; i < N; i++){
      for (int j = 0; j <= T; j++){
        ans = max(ans, dp[i][j]);
      }
    }
    cout << ans << endl;
  }
}
accuracy: 1
time_ms: 470
memory_kb: 6968
final_rank: 9

code_snippet: #include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;
#define stop char nyaa;cin>>nyaa;
#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;
typedef double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);

ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	ll n;
	modint() :n(0) { ; }
	modint(ll m) :n(m) {
		if (n >= mod)n %= mod;
		else if (n < 0)n = (n % mod + mod) % mod;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 1;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

struct swag {
	vector<int> pre, las;
	int lassum;
	void init() {
		lassum = -mod;
	}
	void push_back(int x) {
		las.push_back(x);
		lassum = max(lassum, x);
	}
	void pop_front() {
		if (pre.empty()) {
			int x = -mod;
			per(i, las.size()) {
				x = max(x, las[i]);
				pre.push_back(x);
			}
			las.clear();
			lassum = -mod;
		}
		pre.pop_back();
	}
	int query() {
		int res = lassum;
		if (pre.size())res = max(res, pre.back());
		return res;
	}
};

struct graph {
public:
	int n;
	vector<vector<int>> G, rG;
	vector<bool> used;
	vector<int> vs;

	int mk;
	vector<vector<int>> fG;
	vector<vector<int>> ori;
	vector<int> trans;
	graph(int sz) {
		n = sz;
		G.resize(n);
		rG.resize(n);
		used.resize(n);

		fG.resize(n);
		trans.resize(n, -1);
		ori.resize(n);
	}
	void add_edge(int a, int b) {
		G[a].push_back(b);
		rG[b].push_back(a);
	}
	void dfs(int v) {
		used[v] = true;
		rep(i, G[v].size()) {
			if (!used[G[v][i]])dfs(G[v][i]);
		}
		vs.push_back(v);
	}
	void rdfs(int v, int k) {
		used[v] = true;
		queue<int> q; q.push(v);
		vector<int> c;
		while (!q.empty()) {
			int id = q.front(); q.pop();
			ori[k].push_back(id);
			rep(j, rG[id].size()) {
				int to = rG[id][j];
				if (used[to]) {
					if (trans[to] >= 0)c.push_back(trans[to]);
					continue;
				}
				used[to] = true; q.push(to);
			}
		}
		sort(c.begin(), c.end());
		int len = unique(c.begin(), c.end()) - c.begin();
		rep(i, len) {
			fG[c[i]].push_back(k);
		}
		rep(i, ori[k].size()) {
			trans[ori[k][i]] = k;
		}
	}
	void scc() {
		fill(used.begin(), used.end(), false);
		rep(i, n) {
			if (!used[i])dfs(i);
		}
		fill(used.begin(), used.end(), false);
		int k = 0;
		per(i, (int)vs.size()) {
			if (!used[vs[i]]) {
				rdfs(vs[i], k); k++;
			}
		}
		mk = k;
	}
};

int n, m, T;
void solve() {
	vector<int> p(n), t(n), k(n);
	rep(i, n)cin >> p[i] >> t[i] >> k[i];
	vector<bool> canself(n);
	graph g(n);
	rep(i, m) {
		int a, b; cin >> a >> b; a--; b--;
		if (a == b)canself[a] = true;
		else {
			g.add_edge(a, b);
		}
	}
	g.scc();
	vector<vector<int>> dp(g.mk, vector<int>(T + 1));
	auto add = [&](vector<int>& v, int p, int t, int k) {
		rep(r, t) {
			swag sg; sg.init();
			for (int j = r; j <= T; j += t) {
				int val = v[j] - (j / t) * p;
				sg.push_back(val);
				int nval = sg.query()+(j/t)*p;
				v[j] = nval;
				if ((j / t) >= k)sg.pop_front();
			}
		}
	};
	rep(i, g.mk) {
		if (g.ori[i].size() == 1) {
			int id = g.ori[i][0];
			if (canself[id]) {
				add(dp[i], p[id], t[id], k[id]);
			}
			else {
				add(dp[i], p[id], t[id], 1);
			}
		}
		else {
			for (int id : g.ori[i]) {
				add(dp[i], p[id], t[id], k[id]);
			}
		}

		for (int to : g.fG[i]) {
			rep(j, T + 1) {
				dp[to][j] = max(dp[to][j], dp[i][j]);
			}
		}
	}
	int ans = -mod;
	rep(i, g.mk)rep(j, T + 1)ans = max(ans, dp[i][j]);
	//cout << "ans is ";
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	//cout << fixed << setprecision(10);
	//init_f();
	//init();
	//expr();
	//int t; cin >> t;rep(i, t)
	//solve();
	while (cin >> n >> m >> T, n)
		solve();
	return 0;
}
accuracy: 1
time_ms: 360
memory_kb: 7220
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;

vector<int> val, cmp, z;
int Time, ncmps;

int dfs(int now, const vector<vector<int>>& G) {
    int low = val[now] = ++Time, x;
    z.push_back(now);
    for (auto& e : G[now])
        if (cmp[e] < 0)
            low = min(low, val[e] ?: dfs(e, G));
    if (low == val[now]) {
        do {
            x = z.back();
            z.pop_back();
            cmp[x] = ncmps;
        } while (x != now);
        ncmps++;
    }
    return val[now] = low;
}

void scc(const vector<vector<int>>& G) {
    int N = G.size();
    val.assign(N, 0);
    cmp.assign(N, -1);
    z.clear();
    Time = ncmps = 0;
    for (int i = 0; i < N; i++) {
        if (cmp[i] < 0)
            dfs(i, G);
    }
    for (int i = 0; i < N; i++) {
        cmp[i] = ncmps - cmp[i] - 1;
    }
}


int main() {
    int N, M, T;
    while (cin >> N >> M >> T, N) {
        struct Ad {
            int p, t, k;
        };
        vector<Ad> ads(N);
        for (int i = 0; i < N; i++) {
            int p, t, k;
            cin >> p >> t >> k;
            ads[i] = {p, t, k};
        }
        vector<vector<int>> G(N);
        vector<bool> isloop(N);
        for (int i = 0; i < M; i++) {
            int a, b;
            cin >> a >> b;
            a--;
            b--;
            G[a].emplace_back(b);
            if (a == b)
                isloop[a] = true;
        }

        scc(G);
        vector<vector<int>> Compressed(ncmps);
        for (int i = 0; i < N; i++) {
            Compressed[cmp[i]].emplace_back(i);
        }

        int ans = 0;
        vector dp(ncmps, vector(T + 1, 0));
        for (int i = 0; i < ncmps; i++) {
            auto V = Compressed[i];
            vector<Ad> book;
            if (V.size() == 1 && !isloop[V[0]]) {
                Ad ad = ads[V[0]];
                book.push_back({ad.p, ad.t, 1});
            } else {
                for (auto& idx : V) {
                    book.emplace_back(ads[idx]);
                }
            }
            for (auto& ad : book) {
                auto nap = [&](vector<int>& dp, Ad ad) {
                    for (int j = 0; j < ad.t; j++) {
                        deque<pair<int, int>> deq;
                        for (int k = 0; k * ad.t + j <= T; k++) {
                            int val = dp[k * ad.t + j] - k * ad.p;
                            while (!deq.empty() && deq.back().second <= val)
                                deq.pop_back();
                            deq.push_back({k, val});
                            dp[k * ad.t + j] = deq.front().second + k * ad.p;
                            if (deq.front().first == k - ad.k)
                                deq.pop_front();
                        }
                    }
                };
                nap(dp[i], ad);
            }
            ans = max(ans, dp[i].back());
            vector<int> nxt;
            for (auto& v : V)
                for (auto& idx : G[v])
                    nxt.emplace_back(cmp[idx]);
            nxt.erase(unique(nxt.begin(), nxt.end()), nxt.end());
            for (auto& idx : nxt) {
                for (int j = 0; j <= T; j++) {
                    dp[idx][j] = max(dp[idx][j], dp[i][j]);
                }
            }
        }
        cout << ans << endl;
    }
}
accuracy: 1
time_ms: 410
memory_kb: 7036
final_rank: 7

code_snippet: #include <bits/stdc++.h>
#define ll long long
#define INF 1000000005
#define MOD 1000000007
#define EPS 1e-10
#define rep(i,n) for(int i=0;i<(int)(n);++i)
#define rrep(i,n) for(int i=(int)(n)-1;i>=0;--i)
#define srep(i,s,t) for(int i=(int)(s);i<(int)(t);++i)
#define each(a,b) for(auto& (a): (b))
#define all(v) (v).begin(),(v).end()
#define len(v) (int)(v).size()
#define zip(v) sort(all(v)),v.erase(unique(all(v)),v.end())
#define cmx(x,y) x=max(x,y)
#define cmn(x,y) x=min(x,y)
#define fi first
#define se second
#define pb push_back
#define show(x) cout<<#x<<" = "<<(x)<<endl
#define spair(p) cout<<#p<<": "<<p.fi<<" "<<p.se<<endl
#define sar(a,n) cout<<#a<<":";rep(pachico,n)cout<<" "<<a[pachico];cout<<endl
#define svec(v) cout<<#v<<":";rep(pachico,v.size())cout<<" "<<v[pachico];cout<<endl
#define svecp(v) cout<<#v<<":";each(pachico,v)cout<<" {"<<pachico.first<<":"<<pachico.second<<"}";cout<<endl
#define sset(s) cout<<#s<<":";each(pachico,s)cout<<" "<<pachico;cout<<endl
#define smap(m) cout<<#m<<":";each(pachico,m)cout<<" {"<<pachico.first<<":"<<pachico.second<<"}";cout<<endl

using namespace std;

typedef pair<int,int> P;
typedef pair<ll,ll> pll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<ll> vl;
typedef vector<vl> vvl;
typedef vector<double> vd;
typedef vector<P> vp;
typedef vector<string> vs;

const int MAX_N = 100005;

class SCC{
public:
	vector<vector<int> > G,rG,graph;
	vector<int> vs,cmp;
	vector<bool> used;
	int V,cnt;
	SCC(int node_size){
		V = node_size;
		G.resize(V),rG.resize(V);
		used.resize(V),cmp.resize(V);
	}
	void add_edge(int from,int to){
		G[from].push_back(to);
		rG[to].push_back(from);
	}
	void dfs(int u){
		used[u] = true;
		for(int v : G[u]){
			if(!used[v]){
				dfs(v);
			}
		}
		vs.push_back(u);
	}
	void dfs(int u,const int k){
		used[u] = true;
		cmp[u] = k;
		for(int v : rG[u]){
			if(!used[v]){
				dfs(v,k);
			}
		}
	}
	int solve(){ //強連結成分の数を返す
		fill(used.begin(),used.end(),false);
		rep(i,V){
			if(!used[i]){
				dfs(i);
			}
		}
		fill(used.begin(),used.end(),false);
		cnt = 0;
		for(int i=V-1;i>=0;i--){
			if(!used[vs[i]]){
				dfs(vs[i],cnt++);
			}
		}
		return cnt;
	}
	void make_graph(){
		graph.resize(cnt);
		rep(i,V){
			for(int v : G[i]){
				if(cmp[i] != cmp[v]){
					graph[cmp[v]].push_back(cmp[i]);
				}
			}
		}
	}
};

void knapsaq(vector<int>& dp,vector<int>& v,vector<int>& w,vector<int>& m, int W){
    int n = (int)v.size();
    vector<int> deq(W+1),deqv(W+1);
    rep(i,n){
        rep(a,w[i]){
            int s = 0,t = 0;
            for(int j = 0; j*w[i]+a <= W; j++){
                int val = dp[j*w[i]+a] - j*v[i];
                while(s < t && deqv[t-1] <= val){
                    t--;
                }
                deq[t] = j;
                deqv[t++] = val;
                dp[j*w[i]+a] = deqv[s] + j*v[i];
                if(deq[s] == j-m[i]){
                    s++;
                }
            }
        }
    }
}

void knapsaq2(vector<int>& dp, int v, int w, int W){
	rrep(i,W+1){
		if(i + w <= W) cmx(dp[i+w], dp[i]+v);
	}
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    while(1){
        int n,m,T;
        cin >> n >> m >> T;
        if(n == 0) break;
        vi p(n),t(n),K(n);
        rep(i,n){
            cin >> p[i] >> t[i] >> K[i];
        }
        SCC scc(n);
        vector<bool> used(n,false);
        rep(i,m){
            int a,b;
            cin >> a >> b;
            if(a == b){
                used[a-1] = true;
            }else{
                scc.add_edge(a-1,b-1);
            }
        }
        int cnt = scc.solve();
        vvi id(cnt), v(cnt), w(cnt), M(cnt);
        rep(i,n){
            id[scc.cmp[i]].pb(i);
            v[scc.cmp[i]].pb(p[i]);
            w[scc.cmp[i]].pb(t[i]);
            M[scc.cmp[i]].pb(K[i]);
        }
        // rep(i,cnt){
        //     if(len(v[i]) == 1 && !used[id[i][0]]){
        //         dp[i].resize(T+1,0);
        //         srep(j,w[i][0],T+1){
        //             dp[i][j] = v[i][0];
        //         }
        //     }else{
        //         dp[i] = knapsaq(v[i],w[i],M[i],T);
        //     }
		//	   svec(dp[i]);
        // }
        scc.make_graph();
        auto& G = scc.graph;
        vvi dp(cnt,vi(T+1,0));
        rep(i,cnt){
			vi mx(T+1,0);
			each(v,G[i]){
				rep(j,T+1){
					cmx(mx[j],dp[v][j]);
				}
			}
			if(len(v[i]) == 1 && !used[id[i][0]]){
				knapsaq2(mx,v[i][0],w[i][0],T);
			}else{
				knapsaq(mx,v[i],w[i],M[i],T);
			}
			dp[i] = mx;
        }
        int ans = 0;
        rep(i,cnt){
            cmx(ans, dp[i][T]);
        }
        cout << ans << "\n";
    }
    return 0;
}
accuracy: 1
time_ms: 210
memory_kb: 7088
final_rank: 4

code_snippet: #include <bits/stdc++.h>
using ll = long long;
struct Graph
{
    explicit Graph(const std::size_t v) : V{v}, edge(v), rev_edge(v) {}
    void addEdge(const std::size_t from, const std::size_t to) { edge[from].push_back(to), rev_edge[to].push_back(from); }
    const std::size_t V;
    std::vector<std::vector<std::size_t>> edge;
    std::vector<std::vector<std::size_t>> rev_edge;
};
std::pair<bool, std::vector<std::size_t>> TopologicalSort(const Graph& g)
{
    std::vector<std::size_t> srt, used(g.V, 0);
    auto dfs = [&](auto&& self, const std::size_t s) -> bool {
        if (used[s] == 1) {
            return false;
        } else if (used[s] == 0) {
            used[s] = 1;
            for (const std::size_t to : g.edge[s]) {
                if (not self(self, to)) { return false; }
            }
            used[s] = 2, srt.push_back(s);
        }
        return true;
    };
    for (std::size_t i = 0; i < g.V; i++) {
        if (not dfs(dfs, i)) { return {false, srt}; }
    }
    std::reverse(srt.begin(), srt.end());
    return {true, srt};
}

class StronglyConnectedComponents
{
public:
    StronglyConnectedComponents(const Graph& g) : size(g.V), comp(size, size)
    {
        for (std::size_t i = 0; i < size; i++) {
            for (const std::size_t to : g.edge[i]) { edge.push_back({i, to}); }
        }
        std::vector<std::size_t> st;
        std::vector<bool> used(size, false);
        auto dfs1 = [&](auto&& self, const std::size_t s) -> void {
            used[s] = true;
            for (const std::size_t to : g.edge[s]) {
                if (not used[to]) { self(self, to); }
            }
            st.push_back(s);
        };
        auto dfs2 = [&](auto&& self, const std::size_t s) -> void {
            comp[s] = comp_num;
            for (const std::size_t to : g.rev_edge[s]) {
                if (comp[to] != size) { continue; }
                self(self, to);
            }
        };
        for (std::size_t i = 0; i < size; i++) {
            if (used[i]) { continue; }
            dfs1(dfs1, i);
        }
        for (std::size_t i = 0; i < st.size(); i++) {
            const std::size_t s = st[st.size() - i - 1];
            if (comp[s] != size) { continue; }
            dfs2(dfs2, s), comp_num++;
        }
    }
    const std::vector<std::size_t>& getComp() const { return comp; }
    std::size_t getCompNum() const { return comp_num; }
    Graph toDAG() const
    {
        Graph dag(comp_num);
        for (const auto& e : edge) {
            const std::size_t u = comp[e.first], v = comp[e.second];
            if (u != v) { dag.addEdge(u, v); }
        }
        return dag;
    }

private:
    std::size_t size, comp_num = 0;
    std::vector<std::size_t> comp;
    std::vector<std::pair<std::size_t, std::size_t>> edge;
};
int main()
{
    for (int N, M, T;;) {
        std::cin >> N >> M >> T;
        if (N == 0 and M == 0 and T == 0) { break; }
        Graph g(N);
        std::vector<int> p(N), t(N), k(N);
        for (int i = 0; i < N; i++) { std::cin >> p[i] >> t[i] >> k[i]; }
        for (int i = 0, a, b; i < M; i++) { std::cin >> a >> b, a--, b--, g.addEdge(a, b); }
        StronglyConnectedComponents scc(g);
        const Graph dag = scc.toDAG();
        const auto comp = scc.getComp();
        const auto ord = TopologicalSort(dag).second;
        const int C = scc.getCompNum();
        std::vector<std::vector<int>> cp(C);
        for (int i = 0; i < N; i++) { cp[comp[i]].push_back(i); }
        std::vector<std::vector<ll>> dp(C, std::vector<ll>(T + 1, 0));  //連結成分c内で時間tで最大利益
        for (int j = 0; j < C; j++) {
            const int i = ord[j];
            if (cp[i].size() == 1) {
                bool cir = false;
                for (const int to : g.edge[cp[i][0]]) {
                    if (to == cp[i][0]) { cir = true; }
                }
                if (not cir) { k[cp[i][0]] = 1; }
            }
            std::vector<ll> v, w;
            for (const int node : cp[i]) {
                int K = k[node];
                for (int sz = 1; K > 0; sz *= 2) {
                    const int num = (K >= sz ? sz : K);
                    K -= num;
                    v.push_back(p[node] * num), w.push_back(t[node] * num);
                }
            }
            const int S = v.size();
            for (int j = 0; j < S; j++) {
                for (int k = T - w[j]; k >= 0; k--) { dp[i][k + w[j]] = std::max(dp[i][k + w[j]], dp[i][k] + v[j]); }
            }
            for (const int to : dag.edge[i]) {
                for (int j = 0; j <= T; j++) { dp[to][j] = std::max(dp[to][j], dp[i][j]); }
            }
        }
        ll ans = 0;
        for (int i = 0; i < C; i++) {
            for (int j = 0; j <= T; j++) { ans = std::max(ans, dp[i][j]); }
        }
        std::cout << ans << std::endl;
    }
    return 0;
}
accuracy: 1
time_ms: 200
memory_kb: 10848
final_rank: 12

code_snippet: #include <bits/stdc++.h>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> P;

#define fi first
#define se second
#define repl(i,a,b) for(ll i=(ll)(a);i<(ll)(b);i++)
#define rep(i,n) repl(i,0,n)
#define all(x) (x).begin(),(x).end()
#define dbg(x) cout<<#x"="<<x<<endl
#define mmax(x,y) (x>y?x:y)
#define mmin(x,y) (x<y?x:y)
#define maxch(x,y) x=mmax(x,y)
#define minch(x,y) x=mmin(x,y)
#define uni(x) x.erase(unique(all(x)),x.end())
#define exist(x,y) (find(all(x),y)!=x.end())
#define bcnt __builtin_popcount

#define INF 1e16
#define mod 1000000007

struct UnionFind{
  vector<int> v;
  UnionFind(int n) : v(n, -1) {}
  void init(){ for(int i = 0;i < (int)v.size();i++)v[i]=-1; }
  int find(int x) { return v[x] < 0 ? x : v[x] = find(v[x]); }
  bool unite(int x, int y) {
    x = find(x); y = find(y);
    if (x == y) return false;
    if (-v[x] < -v[y]) swap(x, y);
    v[x] += v[y]; v[y] = x;
    return true;
  }
  bool root(int x) { return v[x] < 0; }
  bool same(int x, int y) { return find(x) == find(y); }
  int size(int x) { return -v[find(x)]; }
};

int N,M,T;
int p[100],t[100],c[100];
bool d[100][100];
vector<int> g[100],idx[100];
bool vis[100];
int dp[100][10001];
bool loop[100];

void dfs(int v){
  vis[v]=true;
  rep(j,T+1)dp[v][j]=0;
  for(int nv : g[v]){
    if(!vis[nv])dfs(nv);
    rep(j,T+1)maxch(dp[v][j],dp[nv][j]);
  }
  for(int i : idx[v]){
    int num=c[i];
    for(int k=1;num>0;k<<=1){
      int ml=min(k,num);
      for(int j=T;j>=t[i]*ml;j--){
        maxch(dp[v][j],dp[v][j-t[i]*ml]+p[i]*ml);
      }
      num-=ml;
    }
  }
}

int main(){
  while(1){
    cin>>N>>M>>T;
    if(N==0)break;
    UnionFind uf(N);
    vector<P> es;
    rep(i,N)cin>>p[i]>>t[i]>>c[i];
    memset(d,0,sizeof(d));
    rep(i,N){
      g[i].clear();
      idx[i].clear();
      vis[i]=false;
      loop[i]=false;
      d[i][i]=true;
    }
    rep(i,M){
      int a,b;
      cin>>a>>b;
      a--;b--;
      if(a==b){
        loop[a]=true;
        continue;
      }
      es.push_back(P(a,b));
      d[a][b]=true;
    }
    M=es.size();
    rep(k,N)rep(i,N)rep(j,N)d[i][j]|=(d[i][k]&d[k][j]);
    rep(i,N)rep(j,N){
      if(d[i][j]&&d[j][i])uf.unite(i,j);
    }
    rep(i,M){
      g[uf.find(es[i].fi)].push_back(uf.find(es[i].se));
    }
    rep(i,N){
      rep(j,N){
        if(uf.find(j)==i)idx[i].push_back(j);
      }
      if(idx[i].size()==1&&!loop[idx[i][0]])c[idx[i][0]]=1;
    }
    int res=0;
    rep(i,N){
      if(idx[i].size()==0)continue;
      if(!vis[i])dfs(i);
      maxch(res,dp[i][T]);
    }
    cout<<res<<endl;
  }
  return 0;
}
accuracy: 1
time_ms: 290
memory_kb: 7060
final_rank: 5

code_snippet: #include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 105

struct Info{
    int point,time,limit;
};

struct GROUP{
    vector<int> nodes;
};

int N,M,T;

GROUP group[NUM]; //強連結成分のグループ
vector<int> G[NUM],GROUP_G[NUM];
vector<int> reverse_G[NUM];
stack<int> S;

bool check[NUM],have_self_link[NUM],G_check[NUM][NUM];
int table[NUM],in_num[NUM];
int dp[NUM][10001];
double sleep[NUM];
Info info[NUM];
int ans;

int group_index;

void dfs(int node_id){
    check[node_id] = true;

    for(int i = 0; i < G[node_id].size(); i++){
        if(!check[G[node_id][i]])dfs(G[node_id][i]);
    }
    S.push(node_id);
}

void reverse_dfs(int node_id){
    check[node_id] = true;

    group[group_index].nodes.push_back(node_id); //group[group_index]にノードを突っ込む
    table[node_id] = group_index;

    for(int i = 0; i < reverse_G[node_id].size(); i++){
        if(!check[reverse_G[node_id][i]])reverse_dfs(reverse_G[node_id][i]);
    }
}


void func(){

    for(int i = 0; i < N; i++){
        G[i].clear();
        reverse_G[i].clear();
        have_self_link[i] = false;
    }

    for(int i = 0; i < N; i++){
        scanf("%d %d %d",&info[i].point,&info[i].time,&info[i].limit);
    }

    int from,to;

    for(int loop = 0; loop < M; loop++){
        scanf("%d %d",&from,&to);
        from--;
        to--;

        if(from == to){
            have_self_link[from] = true; //★強連結成分扱いとする(自分に戻れる)★
            continue;
        }
        G[from].push_back(to);
        reverse_G[to].push_back(from);
    }

    for(int i = 0; i < N; i++)check[i] = false;

    //まずは帰りがけ順を計算
    for(int i = 0; i < N;i++){
        if(!check[i])dfs(i);
    }

    for(int i = 0; i < N;i++)check[i] = false;
    for(int i = 0; i < NUM; i++){
        group[i].nodes.clear();
        GROUP_G[i].clear();
        in_num[i] = 0;
        for(int k = 0; k < NUM; k++){
            G_check[i][k] = false;
        }
    }


    group_index = -1;
    //ノードを、帰りがけ順の逆順に、各強連結成分(グループ)に分解
    while(!S.empty()){
        if(!check[S.top()]){
            group_index++;

            reverse_dfs(S.top());
        }
        S.pop();
    }

    int node_id,adj_node,adj_group;
    //グループ間の有向エッジを探す
    for(int i = 0; i <= group_index; i++){
        for(int k = 0; k < group[i].nodes.size(); k++){
            node_id = group[i].nodes[k];
            for(int a = 0; a < G[node_id].size(); a++){
                adj_node = G[node_id][a];
                adj_group = table[adj_node];
                if(adj_group == i || G_check[i][adj_group] == true)continue;
                G_check[i][adj_group] = true;
                GROUP_G[i].push_back(adj_group);
                in_num[adj_group]++;
            }
        }
    }

    //あらかじめ、強連結成分でなく、かつ自己ループを持たないサイトは、制限個数を1にしておく
    for(int i = 0; i <= group_index; i++){
        if(group[i].nodes.size() == 1 && have_self_link[group[i].nodes[0]] == false){
            info[group[i].nodes[0]].limit = 1;
            //printf("%dは1回\n",group[i].nodes[0]);
        }
    }

    for(int i = 0; i <= group_index; i++){
        dp[i][0] = 0;
        for(int k = 1; k <= T; k++)dp[i][k] = -1;
    }

    ans = 0;

    //トポロジカル順にやる
    queue<int> Q;
    for(int i = 0; i <= group_index; i++){
        if(in_num[i] == 0){
            Q.push(i);
        }
    }

    int group_id,count,mult;

    while(!Q.empty()){
        group_id = Q.front();
        Q.pop();

       for(int i = 0; i < group[group_id].nodes.size(); i++){
            node_id = group[group_id].nodes[i];

            count = info[node_id].limit;
            for (int k = 1; count > 0; k *= 2) { //★★ダブリングナップザック★★
					mult = min(k,count);
					if(info[node_id].time*mult > T)break;
					for (int t = T; t-info[node_id].time*mult >= 0; t--){
						if(dp[group_id][t-info[node_id].time*mult] == -1)continue;
						dp[group_id][t] = max(dp[group_id][t],dp[group_id][t-info[node_id].time*mult]+info[node_id].point*mult);
					}
					count -= mult;
			}
        }

        if(GROUP_G[group_id].size() == 0){ //DAGの終点

            for(int i = 0; i <= T; i++)ans = max(ans,dp[group_id][i]);

        }else{

            for(int i = 0; i < GROUP_G[group_id].size(); i++){
                adj_group = GROUP_G[group_id][i];
                for(int k = 0; k <= T; k++)dp[adj_group][k] = max(dp[adj_group][k],dp[group_id][k]); //dpの情報を引き継ぐ
                in_num[adj_group]--;
                if(in_num[adj_group] == 0){
                    Q.push(adj_group);
                }
            }
        }
    }

    printf("%d\n",ans);
}


int main(){

    while(true){
        scanf("%d %d %d",&N,&M,&T);
        if(N == 0 && M == 0 && T == 0)break;

        func();
    }
    return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 7148
final_rank: 2

code_snippet: #include <stdio.h>
#include <cmath>
#include <algorithm>
#include <cfloat>
#include <stack>
#include <queue>
#include <vector>
#include <string>
#include <iostream>
#include <set>
#include <map>
#include <time.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define NUM 105

struct Info{
    int point,time,limit;
};

struct GROUP{
    vector<int> nodes;
};

int N,M,T;

GROUP group[NUM]; //強連結成分のグループ
vector<int> G[NUM],GROUP_G[NUM];
vector<int> reverse_G[NUM];
stack<int> S;

bool check[NUM],have_self_link[NUM],G_check[NUM][NUM];
int table[NUM],in_num[NUM];
int dp[NUM][10001];
double sleep[NUM];
Info info[NUM];
int ans;

int group_index;

void dfs(int node_id){
    check[node_id] = true;

    for(int i = 0; i < G[node_id].size(); i++){
        if(!check[G[node_id][i]])dfs(G[node_id][i]);
    }
    S.push(node_id);
}

void reverse_dfs(int node_id){
    check[node_id] = true;

    group[group_index].nodes.push_back(node_id); //group[group_index]にノードを突っ込む
    table[node_id] = group_index;

    for(int i = 0; i < reverse_G[node_id].size(); i++){
        if(!check[reverse_G[node_id][i]])reverse_dfs(reverse_G[node_id][i]);
    }
}


void func(){

    for(int i = 0; i < N; i++){
        G[i].clear();
        reverse_G[i].clear();
        have_self_link[i] = false;
    }

    for(int i = 0; i < N; i++){
        scanf("%d %d %d",&info[i].point,&info[i].time,&info[i].limit);
    }

    int from,to;

    for(int loop = 0; loop < M; loop++){
        scanf("%d %d",&from,&to);
        from--;
        to--;

        if(from == to){
            have_self_link[from] = true; //★強連結成分扱いとする(自分に戻れる)★
            continue;
        }
        G[from].push_back(to);
        reverse_G[to].push_back(from);
    }

    for(int i = 0; i < N; i++)check[i] = false;

    //まずは帰りがけ順を計算
    for(int i = 0; i < N;i++){
        if(!check[i])dfs(i);
    }

    for(int i = 0; i < N;i++)check[i] = false;
    for(int i = 0; i < NUM; i++){
        group[i].nodes.clear();
        GROUP_G[i].clear();
        in_num[i] = 0;
        for(int k = 0; k < NUM; k++){
            G_check[i][k] = false;
        }
    }


    group_index = -1;
    //ノードを、帰りがけ順の逆順に、各強連結成分(グループ)に分解
    while(!S.empty()){
        if(!check[S.top()]){
            group_index++;

            reverse_dfs(S.top());
        }
        S.pop();
    }

    int node_id,adj_node,adj_group;
    //グループ間の有向エッジを探す
    for(int i = 0; i <= group_index; i++){
        for(int k = 0; k < group[i].nodes.size(); k++){
            node_id = group[i].nodes[k];
            for(int a = 0; a < G[node_id].size(); a++){
                adj_node = G[node_id][a];
                adj_group = table[adj_node];
                if(adj_group == i || G_check[i][adj_group] == true)continue;
                G_check[i][adj_group] = true;
                GROUP_G[i].push_back(adj_group);
                in_num[adj_group]++;
            }
        }
    }

    //あらかじめ、強連結成分でなく、かつ自己ループを持たないサイトは、制限個数を1にしておく
    for(int i = 0; i <= group_index; i++){
        if(group[i].nodes.size() == 1 && have_self_link[group[i].nodes[0]] == false){
            info[group[i].nodes[0]].limit = 1;
            //printf("%dは1回\n",group[i].nodes[0]);
        }
    }

    for(int i = 0; i <= group_index; i++){
        dp[i][0] = 0;
        for(int k = 1; k <= T; k++)dp[i][k] = -1;
    }

    ans = 0;

    //トポロジカル順にやる
    queue<int> Q;
    for(int i = 0; i <= group_index; i++){
        if(in_num[i] == 0){
            Q.push(i);
        }
    }

    int group_id,count,mult;

    while(!Q.empty()){
        group_id = Q.front();
        Q.pop();

       for(int i = 0; i < group[group_id].nodes.size(); i++){
            node_id = group[group_id].nodes[i];

            count = info[node_id].limit;
            for (int k = 1; count > 0; k *= 2) { //★★ダブリングナップザック★★
					mult = min(k,count);
					for (int t = T; t-info[node_id].time*mult >= 0; t--){
						if(dp[group_id][t-info[node_id].time*mult] == -1)continue;
						dp[group_id][t] = max(dp[group_id][t],dp[group_id][t-info[node_id].time*mult]+info[node_id].point*mult);
					}
					count -= mult;
			}
        }

        if(GROUP_G[group_id].size() == 0){ //DAGの終点

            for(int i = 0; i <= T; i++)ans = max(ans,dp[group_id][i]);

        }else{

            for(int i = 0; i < GROUP_G[group_id].size(); i++){
                adj_group = GROUP_G[group_id][i];
                for(int k = 0; k <= T; k++)dp[adj_group][k] = max(dp[adj_group][k],dp[group_id][k]); //dpの情報を引き継ぐ
                in_num[adj_group]--;
                if(in_num[adj_group] == 0){
                    Q.push(adj_group);
                }
            }
        }
    }

    printf("%d\n",ans);
}


int main(){

    while(true){
        scanf("%d %d %d",&N,&M,&T);
        if(N == 0 && M == 0 && T == 0)break;

        func();
    }
    return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 7204
final_rank: 3

code_snippet: #include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>

#include <iostream>
#include <string>
#include <algorithm>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>

#include <complex>

#include <functional>
#include <cassert>

typedef long long ll;
using namespace std;

#define debug(x) cerr << #x << " = " << (x) << endl;


#define mod 1000000007 //1e9+7(prime number)
#define INF 1000000000 //1e9
#define LLINF 2000000000000000000LL //2e18
#define SIZE 2010

vector<vector<int> > G, rev, G2, rev2;
vector<int> id;
vector<int> idDic;
vector<vector<int> > groupList;
vector<int> group;
vector<vector<int> > dp;

int dfs1(int now, int num=1){
  if(id[now] != -1) return num;

  id[now] = 0;
  
  for(int i=0;i<G[now].size();i++){
    num = dfs1(G[now][i], num);
  }

  id[now] = num;
  idDic[num] = now;
  num++;

  return num;
}

bool dfs2(int now, int g){
  if(group[now] >= 0)
    return false;

  group[now] = g;
  groupList[g].push_back(now);
  
  for(int i=0;i<rev[now].size();i++)
    dfs2(rev[now][i], g);

  return true;
}

vector<int> TopologicalSort(vector<vector<int> > G,int n= -1){
  if(n==-1) n=(int)G.size();
  
  int u;
  vector<int> ret,ret2;
  queue<int> que;
  vector<int> indeg(n+1,0);
  
  for(int i=0;i<n;i++){
    for(int j=0;j<G[i].size();j++){
      indeg[G[i][j]]++;
    }
  }
  
  for(int i=0;i<n;i++){
    if(indeg[i]==0){
      que.push(i);
    }
  }
  
  while(!que.empty()){
    u = que.front();
    que.pop();
    
    ret.push_back(u);
    
    for(int i=0;i<G[u].size();i++){
      indeg[G[u][i]]--;
      if(indeg[G[u][i]]==0){
        que.push(G[u][i]);
      }
    }
  }
  
  if(n==(int)ret.size()){
    return ret;
  }else{
    return ret2;
  }
}

bool solve(){
  int N,M,T;
  int p[SIZE], t[SIZE], k[SIZE];
  int a[SIZE], b[SIZE];
  bool selfloop[SIZE] = {};
  
  scanf("%d%d%d",&N,&M,&T);

  if(N == 0) return false;
  
  G.assign(N, vector<int>());
  rev.assign(N, vector<int>());
  G2.assign(N, vector<int>());
  rev2.assign(N, vector<int>());
  id.assign(N, -1);
  idDic.assign(N, -1);
  group.assign(N, -1);
  groupList.assign(N, vector<int>());

  for(int i=0;i<N;i++)
    scanf("%d%d%d",p+i, t+i, k+i);
  
  for(int i=0;i<M;i++){
    scanf("%d%d",a+i, b+i);
    a[i]--; b[i]--;
    G[a[i]].push_back(b[i]);
    rev[b[i]].push_back(a[i]);

    if(a[i] == b[i])
      selfloop[a[i]] = true;
  }
  
  int num = 1, g = 0;
  for(int i=0;i<N;i++) num = dfs1(i, num);
  for(int i=N;i>=1;i--) g += dfs2(idDic[i], g);
  assert(num == N+1);
  
  bool used[110][110] = {};
  
  for(int i=0;i<M;i++){
    int ga = group[a[i]];
    int gb = group[b[i]];
    if(!used[ga][gb] && ga != gb){
       G2[ga].push_back(gb);
       rev2[gb].push_back(ga);
       used[ga][gb] = true;
    }
  }

  auto vec = TopologicalSort(G2, g);
  dp.assign(g, vector<int>(T+1, -INF));
  int ans = 0;
  
  for(int i=0;i<g;i++){
    int gid = vec[i];
    dp[gid][0] = 0;
    bool flag = groupList[gid].size() > 1 || selfloop[groupList[gid][0]];
    
    for(int j=0;j<rev2[gid].size();j++){
      for(int l=0;l<=T;l++)
        dp[gid][l] = max(dp[gid][l], dp[rev2[gid][j]][l]);
    }
    
    for(int j=0;j<groupList[gid].size();j++){
      int q = groupList[gid][j];
      int curk = flag ? k[q] : 1;
      
      for(int base=0;base<t[q];base++){
        priority_queue<pair<int,int> > pq;
        for(int l=base;l<=T;l+=t[q]){
          while(pq.size() && pq.top().second + curk < l/t[q])
            pq.pop();
          
          if(pq.size()){
            auto pqtop = pq.top();
            if(dp[gid][l] >= 0) pq.push({dp[gid][l] - l/t[q] * p[q], l/t[q]});
            dp[gid][l] = max(dp[gid][l], pqtop.first + l/t[q] * p[q]);
          }else{
            if(dp[gid][l] >= 0) pq.push({dp[gid][l] - l/t[q] * p[q], l/t[q]});
          }
        }
      }
    }

    for(int j=0;j<=T;j++){
      ans = max(ans, dp[gid][j]);
    }
  }

  printf("%d\n",ans);

  return true;
}

int main(){

  while(solve());
  
  return 0;
}
accuracy: 1
time_ms: 440
memory_kb: 7120
final_rank: 8

code_snippet: #include <bits/stdc++.h>
#define int long long
#define MAX_T 10005
#define MAX_V 105
using namespace std;

typedef pair<int,int> P;

/* ?????£?????????????§£ O(|V|+|E|) */
int V; //????????°
vector<int> G[MAX_V]; //??°???????????£??\??????????????¨???
vector<int> rG[MAX_V];//?????????????????????????????°??????
vector<int> vs;       //??°?????????????????????
bool used[MAX_V];     //?????§???????????????
int cmp[MAX_V];       //?±????????????£?????????????????????????????????

void add_edge(int from,int to){
  G[from].push_back(to);
  rG[to].push_back(from);
}

void dfs(int v){
  used[v]=true;
  for(int i=0;i<G[v].size();i++)if(!used[G[v][i]])dfs(G[v][i]);
  vs.push_back(v);
}

void rdfs(int v,int k){
  used[v]=true;
  cmp[v]=k;
  for(int i=0;i<rG[v].size();i++) if(!used[rG[v][i]])rdfs(rG[v][i],k);
}

int scc(){
  memset(used,0,sizeof(used));
  vs.clear();
  for(int v=0;v<V;v++) if(!used[v]) dfs(v);
  
  memset(used,0,sizeof(used));
  int k=0;
  for(int i=vs.size()-1;i>=0;i--)if(!used[vs[i]]) rdfs(vs[i],k++);
  return k;
}

int N, M, T, K, p[MAX_V], t[MAX_V], k[MAX_V], memo[MAX_V];
int dp[MAX_V][MAX_T];

vector<int> G2[MAX_V];
vector<int> nodelist[MAX_V];

void solve(){
    
  memset(dp,-1,sizeof(dp));

  for(int i=0;i<K;i++) dp[i][0]=0;
  
  for(int i=0;i<N;i++)
    nodelist[cmp[i]].push_back(i);
  
  int ans=0;
  
  for(int i=0;i<K;i++){
    
    for(int j=0;j<nodelist[i].size();j++){
      
      int node=nodelist[i][j];
      
      int maxk=k[node];
      
      if(!memo[node]&&nodelist[i].size()==1) maxk=1;
      
      int x=1;
    
      while(maxk){
      
	if(maxk<x) x=maxk;

	int y=t[node]*x, z=p[node]*x;
	
	for(int l=T;l>=0;l--){
	  
	  if(dp[i][l]==-1) continue;
	  
	  if(l+y<=T) dp[i][l+y]=max(dp[i][l+y], dp[i][l]+z);
	}
      
	maxk-=x;
      
	x*=2;
      }

      for(int l=0;l<=T;l++) ans=max(ans,dp[i][l]);
      
    }
    
    for(int j=0;j<G2[i].size();j++)
      for(int l=0;l<=T;l++) dp[G2[i][j]][l]=max(dp[G2[i][j]][l],dp[i][l]);
    
  }
  
  cout<<ans<<endl;
}

void init(){
  
  memset(memo,0,sizeof(memo));
  
  for(int i=0;i<N;i++){
    G[i].clear();
    rG[i].clear();
    G2[i].clear();
    nodelist[i].clear();
  }
  
  vs.clear();
  
}

signed main(){

  while(1){
    
    cin>>N>>M>>T;
    if(!N&&!M&&!T) break;
    
    V=N;
    
    init();
    
    for(int i=0;i<N;i++)
      cin>>p[i]>>t[i]>>k[i];
    
    for(int i=0;i<M;i++){
      int a, b;
      cin>>a>>b;
      if(a==b) memo[a-1]=1;
      add_edge(a-1,b-1);
    }
    
    K=scc();
    
    set<P> S;
    
    for(int i=0;i<N;i++)
      for(int j=0;j<G[i].size();j++)
	
	if(!S.count(P(cmp[i],cmp[G[i][j]]))){
	  
	  if(cmp[i]==cmp[G[i][j]]) continue;
	  
	  S.insert(P(cmp[i],cmp[G[i][j]]));
	  G2[cmp[i]].push_back(cmp[G[i][j]]);
	}
    
    solve();
    
  }
  
  return 0;
}
accuracy: 1
time_ms: 330
memory_kb: 11492
final_rank: 17

code_snippet: #include <bits/stdc++.h>
using namespace std;

using pii = pair<int, int>;

struct edge {
    int from, to;
};

using edges = std::vector<edge>;
using graph = std::vector<edges>;

void add_edge(graph& g, int from, int to) {
    g[from].push_back((edge){from, to});
}

int scc(graph& G, std::vector<int>& cmp) {
    int V = G.size();
    std::vector<std::vector<int>> g(V), rg(V);
    std::vector<bool> used(V, false);
    std::vector<int> vs;
    cmp.resize(V);
    for(int i=0; i<V; ++i) {
        for(auto e : G[i]) {
            g[i].push_back(e.to);
            rg[e.to].push_back(i);
        }
    }
    std::function<void(int)> dfs = [&g, &vs, &used, &dfs](int v) {
        used[v] = true;
        for(auto i : g[v]) {
            if(!used[i]) {
                dfs(i);
            }
        }
        vs.push_back(v);
    };
    std::function<void(int, int)> rdfs = [&rg, &cmp, &used, &rdfs](int v, int k) {
        used[v] = true;
        cmp[v] = k;
        for(int i : rg[v]) {
            if(!used[i]) {
                rdfs(i, k);
            }
        }
    };
    for(int v=0; v<V; ++v) {
        if(!used[v]) {
            dfs(v);
        }
    }
    std::fill(used.begin(), used.end(), false);
    int k = 0;
    for(int i=vs.size()-1; i>=0; --i) {
        if(!used[vs[i]]) {
            rdfs(vs[i], k++);
        }
    }
    return k;
}

std::vector<std::vector<int>> build_graph(graph const& g, std::vector<int> const& cmp, int K) {
    int V = g.size();
    std::vector<std::set<int>> s(K);
    std::vector<std::vector<int>> res(K);
    for(int i=0; i<V; ++i) {
        for(auto e : g[i]) {
            s[cmp[i]].insert(cmp[e.to]);
        }
    }
    for(int i=0; i<K; ++i) {
        for(auto j : s[i]) {
            if(i != j) {
                res[i].push_back(j);
            }
        }
    }
    return res;
}


int main() {
    int N, M, T;
    while(cin >> N >> M >> T, N) {
        graph g(N);
        vector<int> p(N), t(N), k(N);
        vector<bool> self(N);
        for(int i = 0; i < N; ++i) {
            cin >> p[i] >> t[i] >> k[i];
        }
        for(int i = 0; i < M; ++i) {
            int a, b;
            cin >> a >> b;
            a--; b--;
            add_edge(g, a, b);
            if(a == b) {
                self[a] = true;
            }
        }
        
        vector<int> cmp;
        int const K = scc(g, cmp);
        auto g2 = build_graph(g, cmp, K);
        vector<vector<int>> C(K);
        for(int i = 0; i < N; ++i) {
            C[cmp[i]].push_back(i);
        }

        vector<vector<int>> dp(K, vector<int>(T + 1));
        for(int i = 0; i < K; ++i) {
            if(C[i].size() == 1 && !self[C[i][0]]) {
                k[C[i][0]] = 1;
            }
            for(auto v : C[i]) {
                for(int j = 0; j < t[v]; ++j) {
                    deque<pii> deq;
                    for(int l = 0; l * t[v] + j <= T; ++l) {
                        int val = dp[i][l * t[v] + j] - l * p[v];
                        while(deq.size() > 0 && deq.back().second <= val) {
                            deq.pop_back();
                        }
                        deq.emplace_back(l, val);
                        dp[i][l * t[v] + j] = deq.front().second + l * p[v];
                        if(deq.front().first == l - k[v]) {
                            deq.pop_front();
                        }
                    }
                }
                for(auto to : g2[i]) {
                    for(int j = 0; j <= T; ++j) {
                        dp[to][j] = max(dp[to][j], dp[i][j]);
                    }
                }
            }
        }

        int res = 0;
        for(int i = 0; i < K; ++i) {
            res = max(res, dp[i][T]);
        }
        cout << res << endl;
    }
}
accuracy: 1
time_ms: 860
memory_kb: 6812
final_rank: 10

code_snippet: #include <bits/stdc++.h>

using namespace std;

#define int long long
#define all(v) (v).begin(), (v).end()
#define resz(v, ...) (v).clear(), (v).resize(__VA_ARGS__)
#define reps(i, m, n) for(int i = (int)(m); i < (int)(n); i++)
#define rep(i, n) reps(i, 0, n)

template<class T1, class T2> void chmin(T1 &a, T2 b){if(a>b)a=b;}
template<class T1, class T2> void chmax(T1 &a, T2 b){if(a<b)a=b;}

typedef pair<int, int> Pi;
typedef tuple<int, int, int> Ti;
typedef vector<int> vint;

const int inf = 1LL << 55;
const int mod = 1e9 + 7;

struct SCC {
  vector< vector<int> > graph, rgraph, dag;
  vector< pair<int, int> > edges;
  vector<int> cmp, selfloop;
  SCC(int V):graph(V), rgraph(V), cmp(V, -1), selfloop(V, 0){}
  void add_edge(int from, int to) {
    graph[from].push_back(to);
    rgraph[to].push_back(from);
    edges.emplace_back(from, to);
  }
  void dfs(int u, vector<int>& ord, vector<int>& used) {
    if(used[u]) return;
    used[u] = 1;
    for(int v : graph[u]) dfs(v, ord, used);
    ord.push_back(u);
  }
  void rdfs(int u, int& id) {
    if(~cmp[u]) return;
    cmp[u] = id;
    for(int v : rgraph[u]) rdfs(v, id);
  }
  int build() {
    vector<int> ord, used(graph.size(), 0);
    for(int u = 0; u < (int)graph.size(); u++) dfs(u, ord, used);
    reverse(ord.begin(), ord.end());
    int sz = 0;
    for(int u : ord) if(cmp[u] == -1) rdfs(u, sz), sz++;

    dag.resize(sz);
    set< pair<int, int> > st;
    for(auto e : edges) {
      int u = cmp[e.first], v = cmp[e.second];
      if(u == v) {
	selfloop[u] = 1;
	continue;
      }
      if(st.count(make_pair(u, v))) continue;
      dag[u].push_back(v);
      st.emplace(u, v);
    }

    return sz;
  }
};

int N, M, T;
vector<int> p, t, k;

int dp[101][10010];

signed main()
{
  cin.tie(0);
  ios_base::sync_with_stdio(0);
  cout << fixed << setprecision(12);

  while(cin >> N >> M >> T, N+M+T) {
    resz(p, N), resz(t, N), resz(k, N);
    rep(i, N) cin >> p[i] >> t[i] >> k[i];


    SCC graph(N);
    rep(i, M) {
      int a, b;
      cin >> a >> b;
      --a, --b;
      graph.add_edge(a, b);
    }
    graph.build();


    auto& dag = graph.dag;
    auto& cmp = graph.cmp;
    int n = dag.size();
    vector< vector<int> > cmp_id(n);
    rep(i, N) cmp_id[cmp[i]].push_back(i);


    memset(dp, 0, sizeof(dp));
    rep(id, n) {
      for(int i : cmp_id[id]) {
	int lim = (cmp_id[id].size() > 1 || graph.selfloop[id] ? k[i] : 1);
	for(int l = 0; lim > 0; l++) {
	  int num = min(lim, 1LL<<l);
	  for(int j = T; j >= t[i]*num; j--) chmax(dp[id][j], dp[id][j-t[i]*num]+p[i]*num);
	  lim -= num;
	}
      }
      for(int to : dag[id]) rep(j, T+1) chmax(dp[to][j], dp[id][j]);
    }


    int ans = 0;
    rep(i, n) rep(j, T+1) chmax(ans, dp[i][j]);
    cout << ans << endl;
  }

  return 0;
}
accuracy: 1
time_ms: 180
memory_kb: 11168
final_rank: 13