Problem Description
给定一个有向图,每个点ii有点权a_iai,请对于每个点ii,找到ii能到达的点中点权的最大值(包括ii点)。
Input
第一行包含一个正整数T(1\leq T\leq 10)T(1≤T≤10),表示测试数据的组数。
每组数据第一行包含两个正整数n,m(1\leq n\leq 100000,1\leq m\leq 200000)n,m(1≤n≤100000,1≤m≤200000),表示点数和边数。
第二行包含nn个正整,依次表示每个点的点权。
接下来m行,每行包含两个正整数u_i,v_i(1\leq u_i,v_i\leq n,u_i\neq v_i),表示一条u_i\rightarrow v_i的单向边。
Output
对于每组数据输出n行,每行一个整数,第$i$行的数表示$i$点能到达的点中点权的最大值。
输入样例
1
6 6
3 7 5 3 8 5
1 2
2 3
3 1
4 5
5 6
2 6
输出样例
7 7 7 8 8 5
kosaraju算法的应用,在最外面的循环统计强连通分量的个数,在内层dfs统计点的个数
edge不用清空,head需要清空,f需要清空
#include<bits/stdc++.h> using namespace std; const int N=1e5+10,M=2e5+10; int head[M],chead[M]; int vis[N],f[N],q[N]; typedef long long ll; struct _edge { int to,next; }edge[M]; _edge cedge[M]; int cnt=0,ccnt=0,t=0,sum=0; void add_edge(int from,int to) { edge[++cnt].to=to; edge[cnt].next=head[from]; head[from]=cnt; } void cadd_edge(int from,int to) { cedge[++ccnt].to=to; cedge[ccnt].next=chead[from]; chead[from]=ccnt; } void dfs(int x) { vis[x]=1; for(int i=head[x];~i;i=edge[i].next) { int j=edge[i].to; if(!vis[j]) dfs(j); } q[++t]=x; } void dfs2(int x,int y) { vis[x]=0; f[sum]++; for(int i=chead[x];~i;i=cedge[i].next) { int j=cedge[i].to; if(vis[j]) dfs2(j,y); } } int main() { ios::sync_with_stdio(false); cin.tie(0);cout.tie(0); int T;cin>>T; while(T--) { int n,m,x,y; cin>>n>>m; cnt=0,ccnt=0,t=0; memset(f,0,sizeof(f)); memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); memset(chead,-1,sizeof(chead)); for(int i=0;i<m;++i) { cin>>x>>y; add_edge(x,y); cadd_edge(y,x); } for(int i=1;i<=n;++i) { if(!vis[i]) dfs(i); } sum=0; for(int i=n;i>=1;--i) { //cout<<q[i]<<'\n'; if(vis[q[i]]) {sum++;dfs2(q[i],q[i]); } } ll ans=0; for(int i=1;i<=sum;++i) { ans+=(f[i]*(ll)(f[i]-1)/2);//除以2不能放在(f[i]-1)前面会向下取整 //cout<<f[i]<<'\n'; } cout<<ans<<'\n'; } return 0; }
posted on
浙公网安备 33010602011771号