【Codeforces960F】Pathwalks

time limit per test:1 second
memory limit per test:256 megabytes
standard input
standard output

Description
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
input1

3 3
3 1 3
1 2 1
2 3 2

output1

2

input2

5 5
1 3 2
3 2 3
3 4 5
5 4 0
4 5 8

output2

3

题目大意
给出带权,编号为输入顺序的有向边,求最长的编号上升权值上升的路径长度


Analysis
有两种考虑方法
①. 对于每个节点将走向它的边指向编号更大权值更大的边,线段树优化连边,跑一边拓扑。。。好复杂,注意新点个数与新边个数

#include<cstring>
#include<cstdio>
#include<algorithm>
#define M 100100

using namespace std;

int n,m,fir[M],nex[M],_fir[M],_nex[M],top,no[M*10],opl,opv,siz[M*10],opr,que[M*30],head,tail;
int st[M*30],u[M*120],nxt[M*120],tot,d[M*30],f[M*30],v[M*120],cnt,node[M],l1;
struct road{int x,y,e;}r[M];
bool cmp(road a,road b){return a.e<b.e;}

void link(int x,int y,int e){
    v[++top]=e;u[top]=y;nxt[top]=st[x];st[x]=top;++d[y];
}

void clear(int w,int l,int r){
    if(!siz[w])return;
    int m=l+r>>1;no[w]=siz[w]=0;
    clear(w+w,l,m);clear(w+w+1,m+1,r);
}
void inc(int w,int h,int t){
    int tmp=++cnt;++siz[w];
    if(no[w])link(tmp,no[w],0);
    link(no[w]=tmp,opv,1);
    if(h==t)return;
    int m=h+t>>1;
    if(opl<=m)inc(w+w,h,m);else inc(w+w+1,m+1,t);
}
void con(int w,int h,int t){
    if(opl>opr)return;
    if(h>=opl && t<=opr){if(no[w])link(opv,no[w],0);return;}
    int m=h+t>>1;
    if(opl<=m)con(w+w,h,m);if(opr>m)con(w+w+1,m+1,t);
}

int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;i++)scanf("%d %d %d",&r[i].x,&r[i].y,&r[i].e);
    for(int i=1;i<=m;i++){
        nex[i]=fir[r[i].x];fir[r[i].x]=i;
        _nex[i]=_fir[r[i].y];_fir[r[i].y]=i;
    }cnt=m;
    for(int i=1;i<=n;i++){
        l1=0;
        for(int o=fir[i];o;o=nex[o])node[++l1]=o;
        for(int o=_fir[i],a=1;o;o=_nex[o]){
            while(a<=l1 && o<node[a]){
                opl=r[node[a]].e;opv=node[a++];inc(1,0,100000);
            }opl=r[o].e+1;opr=100000;opv=o;con(1,0,100000);
        }
        clear(1,0,100000);
    }
    for(int i=1;i<=cnt;i++)if(!d[i])que[++tail]=i,f[i]=i<=m;
    for(;head^tail;){
        int x=que[++head];
        for(int i=st[x];i;i=nxt[i]){
            f[u[i]]=max(f[u[i]],f[x]+v[i]);d[u[i]]--;
            if(!d[u[i]])que[++tail]=u[i];
        }
    }int ans=0;
    for(int i=1;i<=m;i++)if(f[i]>ans)ans=f[i];
    printf("%d",ans);
    return 0;
}

②. DP,设 f(i,k) f ( i , k ) 表示到了第i个点上一条边权值为k的最长路径。那么按照输入顺序的边进行操作,对于每个i建一棵动态开点的权值线段树即可

#include<cstring>
#include<cstdio>
#include<algorithm>
#define N 2001001
#define W 100000

using namespace std;

int n,m,rt[N],son[N][2],mx[N],cnt,opl,opr,opv;

int query(int w,int h,int t){
    if(!w)return 0;
    if(opl>opr)return 0;
    if(h>=opl && t<=opr)return mx[w];
    int m=h+t>>1,r=0;
    if(opl<=m)r=max(r,query(son[w][0],h,m));
    if(opr>m)r=max(r,query(son[w][1],m+1,t));
    return r;
}
void inc(int &w,int h,int t){
    if(!w)w=++cnt;mx[w]=max(mx[w],opv);
    if(h==t)return;
    int m=h+t>>1;
    if(opl<=m)inc(son[w][0],h,m);else inc(son[w][1],m+1,t);
}

int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;i++)rt[i]=++cnt;
    for(int i=1;i<=m;i++){
        int x,y,v,w;scanf("%d %d %d",&x,&y,&w);
        opl=0;opr=w-1;v=query(rt[x],0,W)+1;
        opl=w;opv=v;inc(rt[y],0,W);
    }int ans=0;
    for(int i=1;i<=n;i++)ans=max(ans,mx[rt[i]]);
    printf("%d\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值