CF960F Pathwalks(动态开点线段树或者动态开点树状数组)

题目描述

题目链接

博客

给定 n 个点 m 条边的有向图,可能不连通,可能有重边,也可能会有自环。求最长的路径(可以经过重复节点),使得这条路径的编号和权值都严格单调递增,其中编号指输入的顺序。路径的长度是指经过边的数量。

输入格式

第一行两个整数 n,m。

第二行到第 m+1 行,每行三个整数 a,b,k,表示顶点 a 与顶点 b 有一条边相连,边权为 k。

输出格式

一行一个整数,表示最长的路径的长度。

1≤n,m,wi​≤105。

题目解析

1.这个题就是用map开了一个二维树状数组

    这个题就相当于对于每一个用到的点开一个map,由于对于1e9一共lowbit次数不超过30次在加上map的复杂度,所以一共的复杂度是n*[lg(n)^2],所以是可以的

2.这个题也可以用线段数,就是少了一个log,就是对于用到的点开一个线段树就行,动态开一下点就行

Code1:

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
int n,m;
const int maxn=1e6+100;
map<int,int>mp[maxn];
int dp[maxn];
int lowbit(int x){
    return x&-x;
}
int update(int u,int pos,int w){
    int ans=0;
    if(!pos){
        mp[u][pos]=max(mp[u][pos],w);
    }
    else{
        for(int i=pos;i<maxn;i+=lowbit(i)){
            mp[u][i]=max(mp[u][i],w);
        }
    }
} 
int query(int u,int pos){
    int ans=mp[u][0];
    for(int i=pos;i>0;i-=lowbit(i)){
        ans=max(ans,mp[u][i]); 
    }
    return ans;
}
int main(){
    cin>>n>>m;
    int ans=0;
    for(int i=1;i<=m;i++){
        dp[i]=1;
        int x,y,z;
        cin>>x>>y>>z;
        dp[i]=max(dp[i],query(x,z-1)+1);
        update(y,z,dp[i]);
        ans=max(ans,dp[i]);
    } 
    cout<<ans<<endl;
}
树状数组

Code2:

还没写;这是学长的代码

/*** keep hungry and calm CoolGuang!***/
#pragma GCC optimize(2)
#pragma GCC optimize("Ofast","unroll-loops","omit-frame-pointer","inline")
#include <bits/stdc++.h>
#include<stdio.h>
#include<queue>
#include<algorithm>
#include<string.h>
#include<iostream>
#define debug(x) cout<<#x<<":"<<x<<endl;
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll INF=1e18;
const int maxn=1e6+6;
const int mod=998244353;
const double eps=1e-7;
inline bool read(ll &num)
{char in;bool IsN=false;
    in=getchar();if(in==EOF) return false;while(in!='-'&&(in<'0'||in>'9')) in=getchar();if(in=='-'){ IsN=true;num=0;}else num=in-'0';while(in=getchar(),in>='0'&&in<='9'){num*=10,num+=in-'0';}if(IsN) num=-num;return true;}
ll n,m,p;
struct node{
    int l,r;
    int w;
}t[maxn*5];
ll dp[maxn];
int cnt = 0;
int root[maxn];
void add(int &x,int l,int r,int pos,int w){
    if(!x) t[x=++cnt].w = w;
    else t[x].w = max(t[x].w,w);
    if(l==r) return ;
    int mid =(l+r)/2;
    if(pos<=mid) add(t[x].l,l,mid,pos,w);
    else add(t[x].r,mid+1,r,pos,w);
}
ll query(int now,int l,int r,int x,int y){
    if(x<=l&&y>=r) return t[now].w;
    ll ans = -INF;
    int mid = (l+r)/2;
    if(x<=mid&&t[now].l)ans = max(ans,query(t[now].l,l,mid,x,y));
    if(y>mid&&t[now].r) ans = max(ans,query(t[now].r,mid+1,r,x,y));
    return ans;
}
int main(){
    read(n);read(m);
    ll ans = 0;
    for(int i=1;i<=m;i++){
        dp[i] = 1;
        int x,y,z;scanf("%d%d%d",&x,&y,&z);
      //  debug(z-1);
        ll temp = query(root[x],0,100000,0,z-1);
        if(temp!=-INF) dp[i] = max(dp[i],temp + 1);
        add(root[y],0,100000,z,dp[i]);
        ans = max(ans,dp[i]);
    }
    printf("%lld\n",ans);
    return 0;
}
/**
* 10 *
0000 1111
**/
线段树

 

 

posted @ 2021-09-14 16:20  lipu123  阅读(189)  评论(0)    收藏  举报