luogu_P3387 【模板】缩点

https://www.luogu.org/problem/P3387

题目背景

缩点+DP

题目描述

给定一个n个点m条边有向图,每个点有一个权值,求一条路径,使路径经过的点权值之和最大。你只需要求出这个权值和。

允许多次经过一条边或者一个点,但是,重复经过的点,权值只计算一次。

输入格式

第一行,n,m

第二行,n个整数,依次代表点权

第三至m+2行,每行两个整数u,v,表示u->v有一条有向边

输出格式

共一行,最大的点权之和。

输入输出样例

输入 #1
2 2
1 1
1 2
2 1
输出 #1
2

说明/提示

n<=10^4,m<=10^5,0<=点权<=1000

算法:Tarjan缩点+DAGdp


 

缩点后拓扑更新

#include<iostream>
#include<cstdio>

#define ri register int
#define u int

namespace opt {

    inline u in() {
        u x(0),f(1);
        char s(getchar());
        while(s<'0'||s>'9') {
            if(s=='-') f=-1;
            s=getchar();
        }
        while(s>='0'&&s<='9') {
            x=(x<<1)+(x<<3)+s-'0';
            s=getchar();
        }
        return x*f;
    }

}

using opt::in;

#define NN 10005
#define MM 100005

#include<algorithm>

namespace aft {

    u h[NN],va[NN],id[NN],cnt(1);

    struct node {
        u to,next;
    } a[MM];

    inline void add(const u &x,const u &y) {
        a[++cnt].to=y,a[cnt].next=h[x],h[x]=cnt;
    }

}

namespace mainstay {

    u h[NN],cnt(1);

    struct node {
        u to,next;
    } a[MM];

    inline void add(const u &x,const u &y) {
        a[++cnt].to=y,a[cnt].next=h[x],h[x]=cnt;
    }

    u stk[NN],va[NN],r,n,team[NN],num,low[NN],dfn[NN];

    void tarjan(const u &x) {
        low[x]=dfn[x]=++num,stk[++r]=x;
        for(ri i(h[x]); i; i=a[i].next) {
            u _y(a[i].to);
            if(!dfn[_y]) {
                tarjan(_y);
                low[x]=std::min(low[x],low[_y]);
            } else if(!team[_y]) low[x]=std::min(low[x],dfn[_y]);
        }
        if(dfn[x]==low[x]) {
            ++n;
            do {
                team[stk[r]]=n;
                aft::va[n]+=va[stk[r--]];
            } while(stk[r+1]^x);
        }
    }

    using aft::id;

    u q[NN],ans[NN];

    inline void solve() {
        u N(in()),M(in());
        for(ri i(1); i<=N; ++i) va[i]=in();
        for(ri j(1); j<=M; ++j) {
            u _a(in()),_b(in());
            add(_a,_b);
        }
        for(ri i(1); i<=N; ++i) {
            if(!dfn[i]) tarjan(i);
        }
        for(ri _x(1); _x<=N; ++_x) {
            for(ri i(h[_x]); i; i=a[i].next) {
                u _y(a[i].to);
                if(team[_x]^team[_y]) {
                    aft::add(team[_x],team[_y]),++id[team[_y]];
                }
            }
        }
        u _r(0),_l(0);
        for(ri i(1); i<=n; ++i) if(!id[i]) q[++_r]=i,ans[i]=aft::va[i];
        while(_l+1<=_r) {
            u _x(q[++_l]);
            for(ri i(aft::h[_x]); i; i=aft::a[i].next) {
                u _y(aft::a[i].to);
                ans[_y]=std::max(ans[_y],ans[_x]+aft::va[_y]);
                if(!--id[_y]) {
                    q[++_r]=_y;
                }
            }
        }
        for(ri i(1);i<=n;++i) ans[0]=std::max(ans[0],ans[i]); 
        printf("%d",ans[0]);
    }

}

int main() {

    //freopen("x.txt","r",stdin);
    std::ios::sync_with_stdio(false);
    mainstay::solve();

}

 

posted @ 2019-10-31 17:49  pai_hoo  阅读(121)  评论(0编辑  收藏  举报