Codeforces Round #261 (Div. 2) - E (459E)

题目连接:http://codeforces.com/contest/459/problem/E

题目大意:给定一张有向图,无自环无重边,每条边有一个边权,求最长严格上升路径长度。(1≤n,m≤3 *10^5)

初见此题觉得以边为点,以点为边,重建一张图,小边权向(通过点)相邻的大边权连边,然后得到一张DAG,跑最长DAG路即可。然而仔细一想,这样新图边数上限可以达到m^2。被否决。

后来想到边权有序化思想(并不知道怎么想到的…可能受kruskal思想影响),按边从大到小排序,然后一条边一条边加入,对于u->v这样一条边,dp[u] = max(dp[u], dp[v] + 1),之所以从大到小排是为了保证状态转移的正确性(与上升路径有关),实际上也就确定了dp的顺序。特殊些的是,对于边权相同的边,不能逐条加入,因为题目要求严格单增,边权相等的时候先加的可能影响后加的转移正确性。因此把边权相同的边同时更新同时加入(用另外一个数组先记下值,再更新dp)。最后答案就是所有点的dp值中取最大。

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;

const int MaxN = 3 * 1e5;
struct EDGE
{
	int u, v, w;
}edge[MaxN + 5];
int n, m, res = 0, ans[MaxN + 5], t[MaxN + 5];

bool cmp(EDGE x, EDGE y)
{
	return x.w > y.w;
}

void Init()
{
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= m; i++)
		scanf("%d%d%d", &edge[i].u, &edge[i].v, &edge[i].w);
	sort(edge + 1, edge + m + 1, cmp);
}

void Solve()
{
	memset(ans, 0, sizeof(ans));
	int head = 1, tail;
	while (head <= m)
	{
		tail = head;
		while (tail <= m - 1 && edge[tail + 1].w == edge[tail].w) tail++;
		for (int i = head; i <= tail; i++) t[edge[i].u] = ans[edge[i].u];
		for (int i = head; i <= tail; i++)
			t[edge[i].u] = max(t[edge[i].u], ans[edge[i].v] + 1);	
		for (int i = head; i <= tail; i++) ans[edge[i].u] = t[edge[i].u];
		head = tail + 1;			
	}
	for (int i = 1; i <= n; i++) res = max(res, ans[i]);
	printf("%d\n", res);
}

int main()
{
	Init();
	Solve();
}

  

posted @ 2015-12-18 17:16  Ro_mantic  阅读(138)  评论(0编辑  收藏  举报