Problem Description
给定一个有向图,每个点ii有点权a_iai​​,请对于每个点ii,找到ii能到达的点中点权的最大值(包括ii点)。

Input
第一行包含一个正整数T(1\leq T\leq 10)T(1T10),表示测试数据的组数。

每组数据第一行包含两个正整数n,m(1\leq n\leq 100000,1\leq m\leq 200000)n,m(1n100000,1m200000),表示点数和边数。

第二行包含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 2023-01-31 16:34  ruoye123456  阅读(119)  评论(0)    收藏  举报