北欧半月谈 2018-06-02
传送门
tarjan缩点后进行拓扑dp求出从点i出发的最大点权和,由于是dfs遍历,所以相当于从终点走到点i的最大点权和。
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> using namespace std; const int N=100000+100,M=500000+100; inline void r(int &x){ x=0; char ch=getchar(); bool f=0; while(!isdigit(ch)) f=ch=='-',ch=getchar(); while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); if(f) x=-x; } struct node{ int to,nxt; }e[M]; int head[N],tot; inline void add(int u,int v){ e[++tot]=(node){v,head[u]}; head[u]=tot; } int dfn[N],low[N],idx; int s[N],top; bool ins[N]; int col[N],colv[N],cnt; void tarjan(int u){ dfn[u]=low[u]=++idx; s[++top]=u; ins[u]=1; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; if(!dfn[v]) { tarjan(v); low[u]=min(low[u],low[v]); } else if(ins[v]) low[u]=min(low[u],dfn[v]); } if(dfn[u]==low[u]){ cnt++; while(s[top]!=u){ ins[s[top]]=0; col[s[top]]=cnt; colv[cnt]++; top--; } ins[u]=0; col[u]=cnt; colv[cnt]++; top--; } } struct ed{ int u,v; }E[M]; int in[N]; int dp[N]; int dfs(int u){ if(dp[u]) return dp[u]; dp[u]=0; for(int i=head[u];i;i=e[i].nxt){ int v=e[i].to; dp[u]=max(dp[u],dfs(v)); } dp[u]+=colv[u]; return dp[u]; } int main(){ int n; r(n); for(int i=1;i<=n;i++){ int v; r(v); add(i,v); E[i]=(ed){i,v}; } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i); memset(e,0,sizeof(e)); memset(head,0,sizeof(head)); tot=0; for(int i=1;i<=n;i++){ int u=E[i].u,v=E[i].v; if(col[u]!=col[v]) add(col[u],col[v]),in[col[v]]++; } for(int i=1;i<=cnt;i++) if(!in[i]) dfs(i); for(int i=1;i<=n;i++) printf("%d\n",dp[col[i]]); return 0; }