CodeForces

题目链接:https://vjudge.net/problem/CodeForces-960F

You are given a directed graph with n nodes and m edges, with all edges having a certain weight.

There might be multiple edges and self loops, and the graph can also be disconnected.

You need to choose a path (possibly passing through same vertices multiple times) in the graph such that the weights of the edges are in strictly increasing order, and these edges come in the order of input. Among all such paths, you need to find the the path that has the maximum possible number of edges, and report this value.

Please note that the edges picked don't have to be consecutive in the input.

Input

The first line contains two integers n and m (1 ≤ n ≤ 100000,1 ≤ m ≤ 100000) — the number of vertices and edges in the graph, respectively.

m lines follows.

The i-th of these lines contains three space separated integers aibi and wi (1 ≤ ai, bi ≤ n0 ≤ wi ≤ 100000), denoting an edge from vertex ai to vertex bi having weight wi

Output

Print one integer in a single line — the maximum number of edges in the path.

Examples

Input
3 3
3 1 3
1 2 1
2 3 2
Output
2
Input
5 5
1 3 2
3 2 3
3 4 5
5 4 0
4 5 8
Output
3

Note

The answer for the first sample input is 2: . Note that you cannot traverse  because edge  appears earlier in the input than the other two edges and hence cannot be picked/traversed after either of the other two edges.

In the second sample, it's optimal to pick 1-st, 3-rd and 5-th edges to get the optimal answer: .

题意:

给出n个结点和m条带权有向边,其中可以有环、自环。一条合法的路径为:路径上边的给出次序(输入次序)和权值都满足严格递增,问最长的合法路径?

题解:

1.由于路径需满足“边的给出次序递增”,即只能从先给出的边走到后给出的边,且又需满足“权值严格单调递增”,所以就是一道类LIS的题目。

2.为每个点开一棵线段树,由于边只有1e5条,故使用动态开点就不会超内存。线段树以边权作为区间,每个结点需记录三个信息:左、右孩子,以及当前值能形成的最长路径。

3.剩下的操作与LIS或二维偏序差不多了。

代码如下:

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <cstdlib>
 5 #include <string>
 6 #include <vector>
 7 #include <map>
 8 #include <set>
 9 #include <queue>
10 #include <sstream>
11 #include <algorithm>
12 using namespace std;
13 typedef long long LL;
14 const double eps = 1e-8;
15 const int INF = 2e9;
16 const LL LNF = 9e18;
17 const int MOD = 1e9+7;
18 const int MAXN = 2e6+10;
19 
20 struct node
21 {
22     int lson, rson, cnt;
23     void init()
24     {
25         lson = rson = -1;
26         cnt = 0;
27     }
28 }q[MAXN];
29 int root[MAXN], tot;
30 
31 void add(int &rt, int l, int r, int val, int cnt)
32 {
33     if(rt==-1)  //动态开点
34     {
35         rt = tot++;
36         q[rt].init();
37     }
38     q[rt].cnt = max(q[rt].cnt,cnt);
39     if(l==r) return;
40 
41     int mid = (l+r)>>1;
42     if(val<=mid) add(q[rt].lson, l, mid, val, cnt);
43     else add(q[rt].rson, mid+1, r, val, cnt);
44 }
45 
46 int query(int rt, int l ,int r, int x,int y)
47 {
48     if(rt==-1) return 0;    //如果此处没有开点,即表明此处没有插入值,直接返回0
49     if(x<=l&&r<=y) return q[rt].cnt;
50 
51     int mid = (l+r)>>1;
52     int ret = 0;
53     if(x<=mid) ret = max(ret, query(q[rt].lson, l, mid, x, y));
54     if(y>=mid+1) ret = max(ret, query(q[rt].rson, mid+1, r, x, y));
55     return ret;
56 }
57 
58 int main()
59 {
60     int n, m;
61     while(scanf("%d%d",&n,&m)!=EOF)
62     {
63         tot = 0;
64         memset(root, -1, sizeof(root));
65         int ans = 0;
66         for(int i = 1; i<=m; i++)
67         {
68             int u, v, w;
69             scanf("%d%d%d",&u,&v,&w);
70             int max_cnt = query(root[u],-1, 100000, -1,w-1);    //最小值为-1,防止w-1溢出范围
71             ans = max(ans, max_cnt+1);
72             add(root[v], -1, 100000, w, max_cnt+1);
73         }
74         printf("%d
", ans);
75     }
76 }
View Code
原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8893616.html