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(); }