【Luogu P2656】采蘑菇

链接:

洛谷

题目大意:

一张图,经过一条路后,边权为原来的乘上这条路的“恢复系数”,再下取整。求最长路。

正文:

发现除了环中的,其它的边不会经过第二次。那么缩点带点权做最长路。

代码:

const int N = 160010, M = 2e5 + 10;

inline ll Read() {
	ll x = 0, f = 1;
	char c = getchar();
	while (c != '-' && (c < '0' || c > '9')) c = getchar();
	if (c == '-') f = -f, c = getchar();
	while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + c - '0', c = getchar();
	return x * f;
}

int n, m, s; 

#define double long double
struct edge {
	int from, to, nxt, val; double w;
}e[M + N];
int head[N], tot;
void Add(int u, int v, int val, double w) {
	e[++tot] = (edge) { u, v, head[u], val, w }, head[u] = tot;
}

int low[N], dfn[N], cnt, col[N], num, colv[N];
int stk[N], top; 
void Tarjan (int u, int val, double w) {
	low[u] = dfn[u] = ++cnt;
	stk[++top] = u;
	for (int i = head[u]; i; i = e[i].nxt) {
		int v = e[i].to;
		if (!dfn[v]) {
			Tarjan(v, e[i].val, e[i].w);
			low[u] = min (low[u], low[v]);
		} else if (!col[v]) low[u] = min (low[u], dfn[v]);
	}
	if (low[u] == dfn[u]) {
		num ++;
		do {
			col[stk[top--]] = num;
		} while (u != stk[top + 1]);
	}
}

struct node {
	int val, key;
	bool operator < (const node &a) const {
		return key < a.key;
	}
};
priority_queue <node> q;
int dis[N], vis[N];
void dij (int s) {
	memset (dis, -1, sizeof dis);
	q.push((node){ s, 0 });
	dis[s] = 0;
	while (!q.empty()) {
		int u = q.top().val; q.pop();
		for (int i = head[u]; i; i = e[i].nxt) {
			int v = e[i].to;
			if (dis[v] < dis[u] + e[i].val) {
				dis[v] = dis[u] + e[i].val;
				if (vis[v]) continue; 
				vis[v] = 1;
				q.push((node) { v, dis[v] });
			}
		}
		vis[u] = 0;
	}
}

int main() {
//	freopen(".in", "r", stdin);
//	freopen(".out", "w", stdout);
	n = Read(), m = Read();
	for (int i = 1; i <= m; i++) {
		int u = Read(), v = Read(), val = Read(); double w;
		scanf ("%Lf", &w);
		Add(u, v, val, w);
	}
	for (int i = 1; i <= n; i++)
		if (!dfn[i]) Tarjan(i, 0, 0);
	for (int i = 1; i <= tot; i++) {
		if (col[e[i].from] == col[e[i].to])
			for (; e[i].val; colv[col[e[i].to]] += e[i].val, e[i].val *= e[i].w);
	}
	s = col[Read()];
	tot = 0;
	memset (head, 0, sizeof head);
	n = num;
	for (int i = 1; i <= m; i++) {
		int u = e[i].from, v = e[i].to;
		u = col[u], v = col[v];
		if (u == v) continue;
		Add(u + n, v, e[i].val, 0);
	}
	for (int i = 1; i <= n; i++)
		Add(i, i + n, colv[i], 0);
	dij(s);
	int ans = 0;
	for (int i = 1; i <= n; i++)
		ans = max(ans, max(dis[i + n], dis[i]));
	printf ("%d\n", ans);
	return 0;
}
posted @ 2021-11-19 16:19  Jayun  阅读(39)  评论(0编辑  收藏  举报