【题目】F. Pathwalks
【题意】给定n个点m条边的有向图,可能不连通有重边有自环。每条边有编号 i 和边权 wi ,求最长的路径(可以经过重复节点)满足编号和边权都严格递增。n,m,wi<=10^5。
【算法】主席树+DP
【题解】这个和LIS十分类似,只要在考虑LIS的树状数组做法的前提下多考虑节点搭配问题,即f[i]=f[j]+1还需要e[j].v=e[i].u。
所以对每个节点建可持久化线段树,然后DP即可。(当然也可以用可持久化树状数组)
复杂度O(n log n)。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 7;
const int up = 1e5;
struct node
{
int lc, rc, v;
node() {lc=rc=v=0;}
}t[maxn*20];
int tot;
int rt[maxn];
int dp[maxn], res;
void update(int& c, int l, int r, int pos, int num)
{
if(!c) c = ++ tot;
t[c].v = max(t[c].v, num);
if(l == r) return;
int mid = (l + r) >> 1;
if(pos <= mid) update(t[c].lc, l, mid, pos, num);
else update(t[c].rc, mid+1, r, pos, num);
}
int query(int c, int l, int r, int k) //smaller than k
{
if(l == r) return t[c].v;
int mid = (l + r) >> 1;
if(k <= mid) return query(t[c].lc, l, mid, k);
else return max( t[t[c].lc].v , query(t[c].rc, mid+1, r, k) );
}
int main()
{
int n, q;
scanf("%d %d", &n, &q);
for(int i = 1;i <= q;i ++) {
int u, v, w; //u --> v , cost w
scanf("%d %d %d", &u, &v, &w);
dp[i] = query(rt[u], 1, up, w-1) + 1;
update(rt[v], 1, up, w, dp[i]);
res = max(res, dp[i]);
}
printf("%d\n", res);
return 0;
}