蒟蒻的垂死挣扎
大佬都在搞这个,我就跟风写一波。
这题题目里明说了是Tarjan缩点+DAG DP,肯定就要这么打嘛,毕竟板子题,怕自己冲学科完回来忘了Tarjan,记录下。
首先是Tarjan的写法,这是个大难点,理解之后倒是挺简单的,具体来说就是用dfs的时间戳来判断是否为强连通分量,标准变量名就是dfn数组记录时间戳,low数组记录 可以到的 最接近根的 点 的时间戳,因为是最接近根,所以每次可以到达或回溯时都要求一次min,这样就防止了环套环的情况,这个倒好理解。然后再是对栈的运用,众所周知,dfs就是有栈的模拟,这里记一个数组str来记录栈中的元素、即还未回溯的点,并用一个bool数组判断是否在栈中。每次找到dfn不为零并仍在栈中的,就用于更新答案——这里防止了一个情况,即排除不能成环但已遍历过的点。遍历过一个点的边后,我们用 if(dfn[k]==low[k]) 判断它为该强连通分量的根,若是,则弹栈,在此题中,将同时弹出(同个强连通块)的所有点的权值压到一个新点中,即可得到点的压缩。
然后我们建一个新图,具体做法为枚举每条边,若边的起点终点不是同一个强连通块内的,则按方向将这两个强连通块连一条有向边,对于其他应用此知识点的题,一般都是采取如上判断方法,如枚举完后判断出度等。
最后用拓扑序做一遍DP,这个就不说了。
上代码!
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define RG register
using namespace std;
inline long long rread()
{
RG long long x=0,o=1;
char ch=getchar();
while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
if(ch=='-') o=-1,ch=getchar();
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
return x*o;
}
int aa[100001],bb[100001],n,m,top,first[10001],p[10001],dfn[10001],low[10001],str[10001],be[10001],cnt,num,sum,si[10001],In[10001],fa[10001],q[10001],aans[10001];
bool b[10001];
struct mona{
int nxt,en;
}s[100001];
inline void Insert(int x,int y)
{
s[++top]=(mona) {first[x],y};
first[x]=top;
}
inline void init()
{
n=rread(),m=rread();
for(RG int i=1;i<=n;i++) p[i]=rread();
for(RG int i=1;i<=m;i++)
{
int x=aa[i]=rread(),y=bb[i]=rread();
Insert(x,y);
}
}
void Dfs(int k)
{
low[k]=dfn[k]=(++cnt);
b[k]=1;
str[++num]=k;
for(RG int i=first[k];i;i=s[i].nxt)
{
int en=s[i].en;
if(!dfn[en])
{
Dfs(en);
low[k]=min(low[k],low[en]);
}
else if(b[en]) low[k]=min(low[k],dfn[en]);
}
if(low[k]==dfn[k])
{
int j;
sum++;
do
{
j=str[num--];
be[j]=sum;
b[j]=0;
si[sum]+=p[j];
}while(k!=j);
}
}
inline void Build()
{
memset(first,0,sizeof(first));
memset(s,0,sizeof(s));
top=0;
for(RG int i=1;i<=m;i++)
if(be[aa[i]]!=be[bb[i]]) In[be[bb[i]]]++,Insert(be[aa[i]],be[bb[i]]);
}
inline void Top_sort()
{
int top=0,tail=0,mmax=0;
for(RG int i=1;i<=sum;i++)
if(!In[i]) q[++tail]=i;
while(top<tail)
{
top++;
aans[q[top]]+=si[q[top]];
mmax=max(mmax,aans[q[top]]);
for(RG int i=first[q[top]];i;i=s[i].nxt)
{
In[s[i].en]--;
aans[s[i].en]=max(aans[s[i].en],aans[q[top]]);
if(!In[s[i].en]) q[++tail]=s[i].en;
}
}
cout<<mmax;
}
int main()
{
// freopen("0.in","r",stdin);
init();
for(RG int i=1;i<=n;i++)
if(!dfn[i]) Dfs(i);
Build();
Top_sort();
}