当前位置 博文首页 > 文章内容

    P4742 【[Wind Festival]Running In The Sky】

    作者: 栏目:未分类 时间:2020-09-19 14:00:31

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    相信来做这道题的人肯定都学过\(Tarjan\)缩点吧,如果没有建议先去做P3387 【模板】缩点,如果你忘了,建议也去看看

    满足上面要求后,你会惊奇发现,这两道题基本一样,唯一的差别就是这道题需要记录最大点权,比模板题多一个要求

    但其实这很好想,在缩点的时候,我们另开一个数组记录每一个缩点之后的最值,其余部分完全一样。至于程序我就不贴了

    然后就是跑最大值,其实就是跑最长路,我们可以使用拓扑,记忆化搜索或者DP,但是之前做的时候用的是拓扑,这里就只说拓扑的做法

    我们用\(dis\)表示到达该点时的最长路,\(maxn\)表示到达该点的最长路上的最大点权

    在拓扑跑最长路的过程中,每更新一次最长路,就意味着这条最长路发生了改变,所以这个时候我们应当把\(maxn\)清空,重新更新一次最大点权,不然就会出错,在最后更新答案时,也要注意这个地方

    #include <bits/stdc++.h>
    using namespace std;
    int n,m,ti,cnt,top,tot,ans=-99999999,sum,a[5000010],q[5000010],in[5000010],dis[5000010],pre[5000010],poi[5000010];
    int dfn[5000010],low[5000010],vis[5000010],num[5000010],fir[5000010],head[5000010],heads[5000010],maxn[5000010];
    int x[5000010],y[5000010];
    
    struct node {
    	int to,net;
    } e[5000010],es[5000010];
    
    void add(int u,int v) {
    	e[++tot].to=v;
    	e[tot].net=head[u];
    	head[u]=tot;
    }
    
    void adds(int u,int v) {
    	es[++tot].to=v;
    	es[tot].net=heads[u];
    	heads[u]=tot;
    }
    
    void tarjan(int x) {
    	vis[x]=1;
    	q[++top]=x;
    	dfn[x]=low[x]=++ti;
    	for(int i=head[x];i;i=e[i].net) {
    		int v=e[i].to;
    		if(!dfn[v]) {
    			tarjan(v);
    			low[x]=min(low[x],low[v]);
    		}
    		else {
    			if(vis[v]) low[x]=min(low[x],dfn[v]);
    		}
    	}
    	if(low[x]==dfn[x]) {
    		++cnt;
    		while(q[top+1]!=x) {
    			vis[q[top]]=0;
    			fir[q[top]]=cnt;
    			num[cnt]+=a[q[top]];
    			poi[cnt]=max(poi[cnt],a[q[top]]); //记录缩完点之后的最大点权 
    			top--;
    		}
    	}
    }
    
    inline void topo() {
    	queue<int> q;
    	for(register int i=1;i<=cnt;i++) {
    		dis[i]=num[i];
    		maxn[i]=poi[i];
    		if(!in[i]) q.push(i);
    	} //记得初始化 
    	while(!q.empty()) {
    		int xx=q.front();
    		q.pop();
    		for(register int i=heads[xx];i;i=es[i].net) {
    			int v=es[i].to;
    			if(dis[xx]+num[v]>dis[v]) { //更新最大边权之和
    				maxn[v]=0;             //记得清空,因为更换了路径 
    				maxn[v]=max(poi[v],maxn[xx]);
    				dis[v]=dis[xx]+num[v];
    			}else if(dis[xx]+num[v]==dis[v]){
    				maxn[v]=max(maxn[v],maxn[xx]);
    			}//注意判断边权相同的情况,此时点权可能更大 
    			if(--in[v]==0) q.push(v);
    		}
    	}
    }
    
    int main() {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    	for(int i=1;i<=m;i++) {
    		scanf("%d%d",&x[i],&y[i]);
    		add(x[i],y[i]);
    	}
    	for(int i=1;i<=n;i++) {
    		if(!dfn[i]) tarjan(i);
    	}
    	tot=0;
    	for(int i=1;i<=m;i++) {
    		if(fir[x[i]]!=fir[y[i]]){
    			adds(fir[x[i]],fir[y[i]]);
    			++in[fir[y[i]]];
    		}
    	}
    	topo();
    	for(int i=1;i<=cnt;i++) {
    		if(ans<dis[i]) {
    			ans=dis[i];
    			sum=0;  //这个地方我最开始一直没考虑到(但是边权我却改了),95分调了很久 
    			sum=max(sum,maxn[i]);
    		}else if(ans==dis[i]){
    			ans=dis[i];
    			sum=max(sum,maxn[i]);
    		}//和上面topo一样的思路 
    	}
    	printf("%d %d",ans,sum);
    	return 0;
    }