最大点权
Time Limit: 3000/1000 MS (Java/Others)
Memory Limit: 65535/100000 K (Java/Others)
Problem Description
给定一个有向图,每个点i有点权ai,请对于每个点i,找到i能到达的点中点权的最大值(包括i点)。
Input
第一行包含一个正整数
T
T
T
(
1
≤
T
≤
10
)
(1≤T≤10)
(1≤T≤10),表示测试数据的组数。
每组数据第一行包含两个正整数 n , m n,m n,m ( 1 ≤ n ≤ 100000 , 1 ≤ m ≤ 200000 ) (1≤n≤100000,1≤m≤200000) (1≤n≤100000,1≤m≤200000),表示点数和边数。
第二行包含 n n n个正整数 a 1 , a 2 , … , a n ( 1 ≤ a i ≤ 1 0 9 ) a1,a2,…,an(1≤a_i≤10^9) a1,a2,…,an(1≤ai≤109),依次表示每个点的点权。
接下来
m
m
m行,每行包含两个正整数
u
i
,
v
i
(
1
≤
u
i
,
v
i
≤
n
,
u
i
≠
v
i
)
u_i,v_i(1≤u_i,v_i≤n,u_i≠v_i)
ui,vi(1≤ui,vi≤n,ui=vi),表示一条
u
i
→
v
i
u_i→v_i
ui→vi的单向边。
Output
对于每组数据输出n行,每行一个整数,第i行的数表示i点能到达的点中点权的最大值。
Sample Input
1
6 6
3 7 5 3 8 5
1 2
2 3
3 1
4 5
5 6
2 6
Sample Output
7
7
7
8
8
5
强连通分量 + 记忆化搜索
#include <bits/stdc++.h>
using namespace std;
#define MAIN signed main()
#define IOS std::ios::sync_with_stdio(false)
#define pb push_back
typedef long long ll;
typedef pair<int,int> pii;
typedef vector<int> vi;
const int maxn = 1e5+5;
int w[maxn];//weight
vi g1[maxn], g2[maxn],g3[maxn]; //正向图 ,反向图 ,缩点图
int q[maxn], idx;//pop stack sequence
bool vis[maxn];
int p[maxn]; //set
int dp[maxn], mx[maxn];
void dfs1(int x)
{
vis[x] = true;
int len = g1[x].size();
for(int i=0;i<len;++i) if(!vis[g1[x][i]]) dfs1(g1[x][i]);
q[++idx] = x;
}
void dfs2(int x,int father)
{
vis[x] = false;
p[x] = father;
mx[father] = max(w[x], mx[father]);
int len = g2[x].size();
for(int i=0;i<len;++i) if(vis[g2[x][i]]) dfs2(g2[x][i],father);
}
int dfs(int x) //记忆化搜索
{
if(dp[x]) return dp[x];
dp[x] = mx[x];
int len = g3[x].size();
for(int i=0;i<len;++i)
{
dp[x] = max(dp[x], dfs(g3[x][i]));
}
return dp[x];
}
void solve()
{
int n ,m, a, b;
scanf("%d%d",&n,&m);
memset(q,0,sizeof q);
memset(vis,0,sizeof vis);
memset(mx,0,sizeof mx);
memset(dp,0,sizeof dp);
memset(p,0,sizeof p);
idx = 0;
for(int i=1;i<=n;++i)
{
scanf("%d",&w[i]);
}
while(m--)
{
scanf("%d%d",&a,&b);
g1[a].pb(b);
g2[b].pb(a);
}
for(int i=1;i<=n;++i) if(!vis[i]) dfs1(i);
for(int i=n;i;--i ) if(vis[q[i]]) dfs2(q[i],q[i]);
for(int i=1;i<=n;++i)
{
int len = g1[i].size();
for(int j=0;j<len;++j)
{
if(p[i] == p[g1[i][j]]) continue;
g3[p[i]].pb(p[g1[i][j]]);
}
}
for(int i=1;i<=n;++i)
{
// int len = g3[i].size();
// printf("%d->",i);
// for(int j=0;j<len;++j)
// {
// printf("%d ",g3[i][j]);
// }
// printf("\n");
// printf("%d\n",mx[i]);
printf("%d\n",dfs(p[i]));
}
for(int i=1;i<=n;++i) g1[i].clear(), g2[i].clear(), g3[i].clear();
}
MAIN
{
int T;
scanf("%d",&T);
for(int i=1;i<=T;++i)
{
solve();
}
return 0;
}
/*
2
6 6
3 7 5 3 8 5
1 2
2 3
3 1
4 5
5 6
2 6
6 7
3 7 5 3 8 5
1 2
2 3
3 1
4 5
5 6
2 6
6 4
*/