E. Pashmak and Graph
题意:一个带权有向图,没有重边,没有自环。求图的最长路径长度,使得该路径每一条边权都严格递增。
思路:先排序,然后dp。dp[u]表示以u为起点的最长递增路径长度,len[u]表示以u为起点的最长递增路径的第一条边权。权值递减扫描所有边,状态转移:dp[u]=max(dp[u],dp[v]+1)(存在边uv且权w(u,v)<len(v))。但是这个题发现满足转移条件不能立即进行状态转移,因为有权相同的边,如果立即转移可能会影响这些边的转移。处理方法是用一个队列把能转移的边先存起来,直到扫描到权减小以后,一次性将他们全部转移。
#include <iostream>
#include <stdio.h>
#include <cmath>
#include <algorithm>
#include <iomanip>
#include <cstdlib>
#include <string>
#include <memory.h>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <ctype.h>
#define INF 1000000
#define ll long long
#define min3(a,b,c) min(a,min(b,c))
#define max3(a,b,c) max(a,max(b,c))
#define MAXN 100010
using namespace std;
struct edge{
int u;
int v;
int w;
};
edge E[600010];
bool cmp(edge e1,edge e2){
return e1.w<e2.w;
}
int dp[300010];
int len[300010];
queue<int> que;
queue<int> update;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
int n;//点
int m;//边
while(cin>>n>>m){
memset(dp,0,sizeof(dp));
for(int i=1;i<=n;i++)len[i]=INF;
for(int i=1;i<=m;i++){
cin>>E[i].u>>E[i].v>>E[i].w;
}
sort(E+1,E+m+1,cmp);
int ans=0;
for(int i=m;i>=1;i--){
if(E[i].w!=E[i+1].w){//一次性转移
while(!que.empty()){
int cur=que.front();que.pop();
len[cur]=E[i+1].w;
dp[cur]=max(dp[cur],update.front());update.pop();
ans=max(ans,dp[cur]);
}
}
if( dp[E[i].u]<dp[E[i].v]+1 && (E[i].w<len[E[i].v]) ){//存在队列中
update.push(dp[E[i].v]+1);
que.push(E[i].u);
}
}
while(!que.empty()){
int cur=que.front();que.pop();
dp[cur]=max(dp[cur],update.front());update.pop();
ans=max(ans,dp[cur]);
}
cout<<ans<<endl;
}
return 0;
}