Codeforces Round #447 (Div. 2) E (tarjan + dp)

Ralph is going to collect mushrooms in the Mushroom Forest.

There are m directed paths connecting n trees in the Mushroom Forest. On each path grow some mushrooms. When Ralph passes a path, he collects all the mushrooms on the path. The Mushroom Forest has a magical fertile ground where mushrooms grow at a fantastic speed. New mushrooms regrow as soon as Ralph finishes mushroom collection on a path. More specifically, after Ralph passes a path the i-th time, there regrow i mushrooms less than there was before this pass. That is, if there is initially x mushrooms on a path, then Ralph will collect x mushrooms for the first time, x - 1 mushrooms the second time, x - 1 - 2 mushrooms the third time, and so on. However, the number of mushrooms can never be less than 0.

For example, let there be 9 mushrooms on a path initially. The number of mushrooms that can be collected from the path is 9, 8, 6 and 3 when Ralph passes by from first to fourth time. From the fifth time and later Ralph can't collect any mushrooms from the path (but still can pass it).

Ralph decided to start from the tree s. How many mushrooms can he collect using only described paths?

Input

The first line contains two integers n and m (1 ≤ n ≤ 106, 0 ≤ m ≤ 106), representing the number of trees and the number of directed paths in the Mushroom Forest, respectively.

Each of the following m lines contains three integers xy and w (1 ≤ x, y ≤ n, 0 ≤ w ≤ 108), denoting a path that leads from tree x to tree y with w mushrooms initially. There can be paths that lead from a tree to itself, and multiple paths between the same pair of trees.

The last line contains a single integer s (1 ≤ s ≤ n) — the starting position of Ralph.

Output

Print an integer denoting the maximum number of the mushrooms Ralph can collect during his route.

Examples

扫描二维码关注公众号,回复: 9583189 查看本文章

Input

2 2
1 2 4
2 1 4
1

Output

16

Input

3 3
1 2 4
2 3 3
1 3 8
1

Output

8

Note

In the first sample Ralph can pass three times on the circle and collect 4 + 4 + 3 + 3 + 1 + 1 = 16 mushrooms. After that there will be no mushrooms for Ralph to collect.

In the second sample, Ralph can go to tree 3 and collect 8 mushrooms on the path from tree 1 to tree 3.

题目大意 :

在一个有向图当中,每条边有各自的边权W, 当你第一次经过这条边的时候,获得的价值为W, 第二次经过时获得的价值为W - 1, 第三次经过获得的价值为W - 1 - 2,以此类推,价值最小降为0,降为0后仍然可以经过,让你输出从一个起点出发,最多可以获得多少价值

思路 :

由于价值降为0后仍然可以经过,所以一个环中的价值是可以全部拿到的,解法自然就是先缩点,然后将每个环中的边权和表示出来,剩下的DAG图求一下最长路。由于边权不断经过是会递减的,所以我们可以通过二分找到最后一次大于0的项记为N,然后求前N项和就好,公式不难推,假设当前是第X项,那么当前项就是上一项的值 - X - 1, 所以求前N项和自然就是N * W - N * (N + 1) * (N - 1) / 6

Accepted code

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

#define sc scanf
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MEM(x, b) memset(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))

typedef long long ll;
const int MOD = 1e9 + 7;
const int MAXN = 1e6 + 100;
const int INF = 0x3f3f3f3f;
inline ll fpow(ll a, ll b){ ll r = 1, t = a; while (b){ if (b & 1)r = (r*t) % MOD; b >>= 1; t = (t*t) % MOD; }return r; }

vector <pair <int, ll>> G[MAXN], Gr[MAXN];
int dfn[MAXN], low[MAXN], tot, scnt;
int st[MAXN], suo[MAXN], n, m, sp, X;
ll dis[MAXN], val[MAXN], max_;
bool vis[MAXN];

void tarjan(int x) {
	dfn[x] = low[x] = ++tot;
	vis[x] = true;
	st[++X] = x;
	for (auto it : G[x]) {
		int vi = it.first;
		if (!dfn[vi]) {
			tarjan(vi);
			Min(low[x], low[vi]);
		}
		else if (vis[vi])
			Min(low[x], low[vi]);
	}
	if (dfn[x] == low[x]) {
		int k;
		scnt++;
		do {
			k = st[X--];
			vis[k] = false;
			suo[k] = scnt;
		} while (k != x);
	}
}
ll dist(ll x) {
	ll l = 1, r = 2e5, mid, ans = 1;  // 二分最后一个大于0的项
	while (l <= r) {
		mid = (l + r) >> 1;
		if (x - mid * (mid - 1) / 2 > 0)
			ans = mid, l = mid + 1;
		else
			r = mid - 1;
	}
	return ans * x - ans * (ans - 1) * (ans + 1) / 6ll;  // 返回前N项和
}
ll dfs(int x) {   // DAG图上的最长路
	if (dis[x])
		return dis[x];
	for (auto it : Gr[x])
		Max(dis[x], dfs(it.first) + it.second);
	return dis[x] += val[x];           // 加上环内的权值和
}

int main()
{
	cin >> n >> m;
	for (int i = 0; i < m; i++) {
		int ui, vi; ll wi;
		sc("%d %d %lld", &ui, &vi, &wi);
		G[ui].push_back({ vi, wi });
	}
	cin >> sp;
	tarjan(sp);
	for (int i = 1; i <= n; i++) {
		for (auto it : G[i]) {
			ll wi = it.second;
			int ui = suo[i], vi = suo[it.first];
			if (ui != vi)
				Gr[ui].push_back({ vi, wi });
			else
				val[ui] += dist(wi);
		}
	}
	sp = suo[sp];
	printf("%lld\n", dfs(sp));
	return 0;  // 改数组大小!!!
}
发布了213 篇原创文章 · 获赞 264 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_43851525/article/details/104153916