P3387

· · 个人记录

【模板】缩点

就是 SCC 缩点,缩完之后图是个 DAG,我们在 DAG 上做 DP 即可。

时间复杂度 O(n+m)

突然发现自己的博客里好像没有关于 Tarjan 的具体讲解。这里简单提一嘴。

简单来说,给每个点两个信息,dfnlow。同时有一个栈来维护。

1. 点在栈中; 2. 存在一条从当前子树中出发的有向边,以该点为终点。 如果我们发现在从 $x$ 回溯之前,有 $dfn_x=low_x$ 说明是 SCC,从栈顶开始弹出直到 $x$ 也被弹出,这些点处于一个 SCC 中。 缩点什么的注意一下要枚举每个节点,再枚举每个节点出发的边。 代码: ```cpp #include<iostream> #include<cstdio> #include<algorithm> #include<queue> #define ll long long using namespace std; const ll N=1e4,M=1e5; ll n,m,u,v,tot,tc,cnt,top,num,ans,h; ll ver[M*2+5],nxt[M*2+5],head[N+5]; ll vc[M*2+5],nc[M*2+5],hc[N+5]; ll stk[N+5],ins[N+5],c[N+5],dfn[N+5],low[N+5]; ll a[N+5],deg[N+5],val[N+5],f[N+5]; queue<ll> q; void add_c(ll u,ll v) { vc[++tc]=v;nc[tc]=hc[u];hc[u]=tc; } void tarjan(ll x) { dfn[x]=low[x]=++num; stk[++top]=x;ins[x]=1; for(ll i=head[x];i;i=nxt[i]) { if(!dfn[ver[i]]) { tarjan(ver[i]);low[x]=min(low[x],low[ver[i]]); } else { if(ins[ver[i]]) low[x]=min(low[x],dfn[ver[i]]); } } if(dfn[x]==low[x]) { cnt++; do { ins[stk[top]]=0; c[stk[top]]=cnt; val[cnt]+=a[stk[top]]; } while(x!=stk[top--]); } } void add(ll u,ll v) { ver[++tot]=v;nxt[tot]=head[u];head[u]=tot; } inline ll read() { ll ret=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();} while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();} return ret*f; } void write(ll x) { static char buf[22];static ll len=-1; if(x>=0) { do{buf[++len]=x%10+48;x/=10;}while(x); } else { putchar('-'); do{buf[++len]=-(x%10)+48;x/=10;}while(x); } while(len>=0) putchar(buf[len--]); } int main() { n=read();m=read(); for(ll i=1;i<=n;i++) a[i]=read(); for(ll i=1;i<=m;i++) { u=read();v=read();add(u,v); } for(ll i=1;i<=n;i++) { if(!dfn[i]) tarjan(i); } for(ll x=1;x<=n;x++) { for(ll i=head[x];i;i=nxt[i]) { if(c[x]==c[ver[i]]) continue; add_c(c[x],c[ver[i]]); deg[c[ver[i]]]++; } } for(ll i=1;i<=cnt;i++) { if(!deg[i]) {q.push(i);f[i]=val[i];} } while(!q.empty()) { h=q.front();q.pop(); for(ll i=hc[h];i;i=nc[i]) { if(--deg[vc[i]]==0) q.push(vc[i]); f[vc[i]]=max(f[vc[i]],f[h]+val[vc[i]]); } } for(ll i=1;i<=cnt;i++) { ans=max(ans,f[i]); } write(ans); return 0; } ```