CF960F Pathwalks [dp+动态开点线段树]

F Pathwalks
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard output
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 ai, bi and wi (1 ≤ ai, bi ≤ n, 0 ≤ 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
inputCopy
3 3
3 1 3
1 2 1
2 3 2
outputCopy
2
inputCopy
5 5
1 3 2
3 2 3
3 4 5
5 4 0
4 5 8
outputCopy
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条边,可能存在重边和自环,每条边都有权值wi,要求一条经过边数最多且经过的边的权值是严格递增且经过的边的相对顺序与输入相对顺序一样的路径,输出路径长度

题解:这个相当于图上的最长上升子序列,仿照最长上升子序列可以使用线段树快速找到到达某个结点的最长路径长度,但是由于最长上升子序列的每个元素的顺序是固定的,所以只需要一个建一个线段树即可,而图中顶点的顺序是不定的,所以需要在每个结点上建立一棵线段树,显然直接建树会MLE,需要动态开点建线段树。又由于经过的边顺序需要按照输入的相对顺序,所以可以边输入边更新线段树边更新结果

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define debug(x) cout<<#x<<" is "<<x<<endl;
const int maxn=1e5+5;
struct node{
    int lson;
    int rson;
    int maxx;
}nod[maxn*70];
int root[maxn],tot;
int query(int rot,int l,int r,int l0,int r0){
    if(!rot)return 0;
    int mid=(l+r)>>1;
    if(l>=l0&&r<=r0)return nod[rot].maxx;
    int ac=0;
    if(mid>=l0)ac=max(ac,query(nod[rot].lson,l,mid,l0,r0));
    if(mid<r0)ac=max(query(nod[rot].rson,mid+1,r,l0,r0),ac);
    return ac;
}
void pushup(int rot){
    nod[rot].maxx=max(nod[nod[rot].lson].maxx,nod[nod[rot].rson].maxx);
}
void update(int &rot,int l,int r,int x,int val){
    if(!rot)rot=++tot;
    if(l==r){
        nod[rot].maxx=max(nod[rot].maxx,val);
        return;
    }
    int mid=(l+r)>>1;
    if(mid>=x)update(nod[rot].lson,l,mid,x,val);
    else update(nod[rot].rson,mid+1,r,x,val);
    pushup(rot);
}
int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    int ans=0;
    for(int i=1;i<=m;i++){
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        int ac=query(root[a],1,maxn-1,1,c)+1;
        ans=max(ans,ac);
        update(root[b],1,maxn-1,c+1,ac);
    }
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值