# [Codeforeces 894E. Ralph and Mushrooms] 缩点+拓扑

## 1. 题目链接

[Codeforeces 894E. Ralph and Mushrooms]

## 2. 题意描述

n$n$个顶点m$m$条边的有向图。第i$i$条边的初始边权为wi$w_i$，第k$k$次经过第i$i$条边的权值为wi01(k1)$w_i-0-1-\ldots -(k-1)$。当wi01(k1)<0$w_i-0-1-\ldots -(k-1)\lt 0$ 时，边权为0$0$

1n106,0m106$1 ≤ n ≤ 10^6, 0 ≤ m ≤ 10^6$

## 4. 实现代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef unsigned long long ull;

const int inf = 0x3f3f3f3f;
const ull infl = 0x3f3f3f3f3f3f3f3f;

#ifdef ___LOCAL_WONZY___
void debug() { cout << endl; }
template<typename T, typename ...R> void debug(T f, R ...r) {
cout << "[" << f << "]";
debug(r...);
}
#endif // ___LOCAL_WONZY___

const int MAXN = 1000006;
int n, m, s;
struct Graph {
struct Edge {
int v, next;
ull w;
} edge[MAXN];
void ini(int n) {
etot = 0;
for (int i = 0; i <= n; ++i) head[i] = -1;
}
void add(int u, int v, ull w) {
edge[etot].v = v; edge[etot].w = w;
}
} G1, G2;
int du[MAXN];
int Low[MAXN], DFN[MAXN], Stack[MAXN], Belong[MAXN];
ull wsum[MAXN];
int Index, top;
int scc;//强连通分量的个数
bool Instack[MAXN];
ull pre[MAXN], ppre[MAXN], psz, ans;

void Tarjan(int u) {
int v;
Low[u] = DFN[u] = ++Index;
Stack[top++] = u;
Instack[u] = true;
for (int i = G1.head[u]; ~i; i = G1.edge[i].next) {
v = G1.edge[i].v;
if (!DFN[v]) {
Tarjan(v);
if (Low[u] > Low[v]) Low[u] = Low[v];
}
else if (Instack[v] && Low[u] > DFN[v]) Low[u] = DFN[v];
}
if (Low[u] == DFN[u]) {
++ scc;
do {
v = Stack[--top];
Instack[v] = false;
Belong[v] = scc;
}
while ( v != u);
}
}

inline ull get_contri(const ull& w) {
int pos = upper_bound(pre, pre + psz, w) - pre;
return w * pos - ppre[pos - 1];
}

ull dp[MAXN];
bool flag[MAXN];
void dfs(int u) {
flag[u] = 1;
for (int i = G2.head[u]; ~i; i = G2.edge[i].next) {
int v = G2.edge[i].v;
if (!flag[v]) dfs(v);
}
}

void bfs() {
dfs(Belong[s]);
for (int u = 1; u <= scc; ++u) {
if (!flag[u]) continue;
for (int i = G2.head[u]; ~i; i = G2.edge[i].next) {
int v = G2.edge[i].v;
++ du[v];
}
}
int u, v; ull w;
queue<int> q;
q.push(Belong[s]);
dp[Belong[s]] = wsum[Belong[s]];
while (!q.empty()) {
u = q.front(); q.pop();
for (int i = G2.head[u]; ~i; i = G2.edge[i].next) {
v = G2.edge[i].v; w = G2.edge[i].w;
-- du[v];
if (du[v] == 0) q.push(v);
dp[v] = max(dp[v], dp[u] + wsum[v] + w);
}
}
for (int i = 1; i <= scc; ++i) ans = max(ans, dp[i]);
}

int main() {
#ifdef ___LOCAL_WONZY___
freopen("input.txt", "r", stdin);
#endif // ___LOCAL_WONZY___
pre[0] = ppre[0] = 0;
for (int i = 1; i < MAXN; ++i) {
pre[i] = pre[i - 1] + i;
ppre[i] = ppre[i - 1] + pre[i];
++ psz;
//手残把pre写成了ppre，无限WA
if(pre[i] > 120000000) break;
}
int u, v; ull w; ans = 0;
scanf("%d %d", &n, &m);
G1.ini(n);
for (int i = 1; i <= m; ++i) {
scanf("%d %d %llu", &u, &v, &w);
}
scanf("%d", &s);
Index = scc = top = 0;
for (int i = 1; i <= n; i++) if (!DFN[i]) Tarjan(i);
G2.ini(scc);
for (u = 1; u <= n; ++u) {
for (int i = G1.head[u]; ~i; i = G1.edge[i].next) {
v = G1.edge[i].v; w = G1.edge[i].w;
if (Belong[u] != Belong[v]) G2.add(Belong[u], Belong[v], w);
else wsum[Belong[v]] += get_contri(w);
}
}
bfs();
printf("%llu\n", ans);
#ifdef ___LOCAL_WONZY___
cout << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC * 1000 << "ms." << endl;
#endif // ___LOCAL_WONZY___
return 0;
}