洛谷P1983 车站分级

这题有三种做法

1. O ( n m 2 )

488ms / 9.61MB / 0.68KB
不用讲,直接贴代码

#include<bits/stdc++.h>
using namespace std;
const int N=1002;
int n,m,i,j,a[N],d[N],ans,f[N],k,vi[N][N],c[N][N],l;
int dfs(int x){
    if (f[x]) return f[x];
    for (int i=1;i<=c[x][0];i++) f[x]=max(f[x],dfs(c[x][i]));
    return ++f[x];
}
int main(){
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;i++){
        scanf("%d",&a[0]);
        for (j=1;j<=a[0];j++) scanf("%d",&a[j]);
        l=1;
        for (j=a[1];j<a[a[0]];j++)
            if (a[l]==j) l++;
            else for (k=1;k<=a[0];k++)
                    if (!vi[a[k]][j]) c[a[k]][++c[a[k]][0]]=j,vi[a[k]][j]=1;
    }
    for (i=1;i<=n;i++) ans=max(ans,dfs(i));
    printf("%d",ans);
}

2. O ( n m )

244ms / 13.34MB / 0.69KB
原本要连 n 2 条边:

但是,如果在中间添加一个虚点,就可以变成 2 n 条边:

#include<bits/stdc++.h>
using namespace std; 
int n,m,ans,a[2003],s,i,j,u,to[2003][2003],uans[2003],sto[2003];
void dfs(int u){
    if (uans[u]) return;
    for(int i=1;i<=to[u][0];i++){
        if(!uans[to[u][i]]) dfs(to[u][i]);
        uans[u]=max(uans[u],uans[to[u][i]]+1);
    }
    if(u>n) uans[u]--;
    ans=max(ans,uans[u]);
}
int main(){
    scanf("%d%d",&n,&m);
    for (i=1;i<=m;i++){
        scanf("%d",&s);
        for (j=1;j<=s;j++) scanf("%d",&a[j]),sto[a[j]]=i,to[n+i][++to[n+i][0]]=a[j];
        for (u=a[1]+1;u<a[s];u++) 
            if (sto[u]!=i) to[u][++to[u][0]]=n+i;    
    }
    for (i=1;i<=n;i++) 
        if (!uans[i]) dfs(i);
    printf("%d",++ans);
}

3. O ( n m l o g n )

72ms / 7.75MB / 1.62KB
看起来还是第二种方法更优,但是实际很快
有这样一棵线段树,每个点都和父亲连边:

每加进一个区间,则把线段树上对应区间和那个点连起来,比如加 [ 1 , 3 ] 这个区间:

代码是参考这里的,老师给我们讲过,但我写不出

#include<bits/stdc++.h>
using namespace std;
const int N=1500;
int h[N<<3],n,m,i,st[N],in[N<<3],num[N],dis[N<<3],dep[N<<3],tot,tp,q[N<<5],he,ta,cnt,j,ans;
struct node{
    int to,ne;
}e[N*700];
inline char gc(){
    static char buf[100000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
#define gc getchar
inline int read(){
    int x=0,fl=1;char ch=gc();
    for (;ch<48||ch>57;ch=gc())if(ch=='-')fl=-1;
    for (;48<=ch&&ch<=57;ch=gc())x=(x<<3)+(x<<1)+(ch^48);
    return x*fl;
}
void add(int x,int y){
    in[y]++;
    e[++tot]=(node){y,h[x]};
    h[x]=tot;
}
void build(int t,int l,int r){
    tp=max(tp,t);
    if (l==r){
        num[l]=t;
        dis[t]=1;
        return;
    }
    int mid=l+r>>1;
    add(t<<1,t);
    build(t<<1,l,mid);
    add(t<<1|1,t);
    build(t<<1|1,mid+1,r);
}
void update(int t,int l,int r,int x,int y,int tmp){
    if (x<=l && r<=y){
        add(t,tmp);
        return;
    }
    int mid=l+r>>1;
    if (x<=mid) update(t<<1,l,mid,x,y,tmp);
    if (mid<y) update(t<<1|1,mid+1,r,x,y,tmp);
}
void bfs(){
    for (int i=1;i<=tp;i++)
        if (!in[i]) q[ta++]=i,dep[i]=dis[i];
    while (he<ta){
        int u=q[he++];
        for (int i=h[u],v;i;i=e[i].ne){
            v=e[i].to;
            dep[v]=max(dep[v],dep[u]+dis[v]);
            if (!(--in[v])) q[ta++]=v;
        }
    }
}
int main(){
    n=read();m=read();
    build(1,1,n);
    for (i=1;i<=m;i++){
        cnt=read();tp++;
        for (j=1;j<=cnt;j++) st[j]=read();
        for (j=1;j<cnt;j++){
            add(tp,num[st[j]]);
            if (st[j]+1<=st[j+1]-1) update(1,1,n,st[j]+1,st[j+1]-1,tp);
        }
        add(tp,num[st[cnt]]);
    }
    bfs();
    for (i=1;i<=n;i++) ans=max(ans,dep[num[i]]);
    printf("%d",ans);
}

猜你喜欢

转载自blog.csdn.net/xumingyang0/article/details/81021793