• 点对统计
  • 最大点权

点对统计

Problem Description

给定一个有向图,统计有多少点对u,v(1≤u<v≤n)u,v(1≤u<v≤n)u,v(1≤u<v≤n)满足uuu可以到达vvv,且vvv可以到达uuu。

Input

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

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

接下来mmm行,每行包含两个正整数ui,vi(1≤ui,vi≤n,ui≠vi)u_i,v_i(1≤u_i,v_i≤n,u_i≠v_i)ui​,vi​(1≤ui​,vi​≤n,ui​​=vi​),表示一条ui→viu_i→v_iui​→vi​的单向边。

Output

对于每组数据输出一行一个整数,即满足条件的点对数。

Sample Input

1
6 7
1 2
2 3
3 1
4 5
5 6
6 4
2 6

Sample Output

6

思路

用Kosaraju算法求出每个强连通分量的大小,记录到f[cnt]f[cnt]f[cnt]中。满足要求的点对数量为∑Cf[i]2=∑f[i]×(f[i]−1)2\sum C_{f[i]}^2=\sum\frac{f[i]\times (f[i]-1)}{2}∑Cf[i]2​=∑2f[i]×(f[i]−1)​。

#include<cstdio>
using namespace std;
const int maxn=1e5+5,Emaxn=2e5+5;
int n,m,u,v,q[maxn],qtot,vis[maxn],f[maxn],ftot;
int head[maxn],ver[Emaxn],Next[Emaxn],tot;
int rhead[maxn],rver[Emaxn],rNext[Emaxn],rtot;void add(int x,int y){ver[++tot]=y,Next[tot]=head[x],head[x]=tot;rver[++rtot]=x,rNext[rtot]=rhead[y],rhead[y]=rtot;
}void rdfs(int x){vis[x]=1;for(int i=rhead[x];i;i=rNext[i]){if(vis[rver[i]])  continue;rdfs(rver[i]);}q[qtot++]=x;
}int dfs(int x){vis[x]=0;   int ret=1;for(int i=head[x];i;i=Next[i]){if(!vis[ver[i]]) continue;ret+=dfs(ver[i]);}return ret;
}void solve(){tot=rtot=qtot=ftot=0;for(int i=0;i<maxn;i++) head[i]=rhead[i]=0;scanf("%d%d",&n,&m);for(int i=0;i<m;i++)    scanf("%d%d",&u,&v),add(u,v);for(int i=1;i<=n;i++)   if(!vis[i]) rdfs(i);for(int i=qtot-1;i>=0;i--)if(vis[q[i]])  f[ftot++]=dfs(q[i]);long long ans=0;for(int i=0;i<ftot;i++) ans+=1LL*f[i]*(f[i]-1)/2;printf("%lld\n",ans);
}int main(){int te;scanf("%d",&te);while(te--) solve();
}

最大点权

Problem Description

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

Input

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

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

第二行包含n个正整数a1,a2,…,an(1≤ai≤109)a_1,a_2,…,a_n(1≤a_i≤10^9)a1​,a2​,…,an​(1≤ai​≤109),依次表示每个点的点权。

接下来m行,每行包含两个正整数ui,vi(1≤ui,vi≤n,ui≠vi)u_i,v_i(1≤u_i,v_i≤n,u_i≠v_i)ui​,vi​(1≤ui​,vi​≤n,ui​​=vi​),表示一条ui→viu_i→v_iui​→vi​的单向边。

Output

对于每组数据输出nnn行,每行一个整数,第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

推荐测试输入

1
6 6
1 2 5 4 6 10
1 6
6 2
2 1
4 2
3 4
5 3

输出

10
10
10
10
10
10

思路

直接在原图上进行记忆化搜索(或dp)是无法得到正确答案的,因为原图可能有环,不满足“无后效性”这一条件。

可以新建一个图,将原图中的每个强连通分量缩为一个点,这样就得到了一个有向无环图(DAG),在这基础上进行记忆化搜索(或dp)即可。

注意在构建完DAG之后,在记忆化搜索之前,应该用去掉的那些点的权值更新保留下来的点的权值。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e5+5,Emaxn=2e5+5;
int n,m,u[Emaxn],v[Emaxn],a[maxn],vis[maxn],q[maxn],qtot,f[maxn],ans[maxn];
int head[maxn],ver[Emaxn],Next[Emaxn],tot;
int rhead[maxn],rver[Emaxn],rNext[Emaxn],rtot;void add(int u,int v){ver[++tot]=v,Next[tot]=head[u],head[u]=tot;rver[++rtot]=u,rNext[rtot]=rhead[v],rhead[v]=rtot;
}void rdfs(int x){vis[x]=1;for(int i=rhead[x];i;i=rNext[i]){if(vis[rver[i]]) continue;rdfs(rver[i]);}q[qtot++]=x;
}void dfs(int x,int y){vis[x]=0;for(int i=head[x];i;i=Next[i]){if(!vis[ver[i]])    continue;dfs(ver[i],y);}f[x]=y; ans[y]=max(ans[y],a[x]);
}void dfsAns(int x){vis[x]=1;   ans[f[x]]=max(a[x],ans[f[x]]);for(int i=head[x];i;i=Next[i]){if(!vis[ver[i]]) dfsAns(ver[i]);ans[x]=max(ans[x],ans[ver[i]]);}
}void solve(){tot=rtot=qtot=0;memset(head,0,sizeof(head));memset(rhead,0,sizeof(rhead));memset(vis,0,sizeof(vis));memset(ans,0,sizeof(ans));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",&u[i],&v[i]),add(u[i],v[i]);for(int i=1;i<=n;i++)   if(!vis[i]) rdfs(i);for(int i=qtot-1;i>=0;i--)  if(vis[q[i]])   dfs(q[i],q[i]);memset(head,0,sizeof(head));memset(rhead,0,sizeof(rhead));    tot=rtot=0;for(int i=1;i<=m;i++)   if(f[u[i]]!=f[v[i]])    add(f[u[i]],f[v[i]]);for(int i=1;i<=n;i++)   if(!vis[i]) dfsAns(i);for(int i=1;i<=n;i++)   printf("%d\n",ans[f[i]]);
}int main(){int te;scanf("%d",&te);while(te--) solve();
}

杭电ACM-LCY算法进阶培训班-专题训练(强连通分量)相关推荐

  1. 杭电ACM-LCY算法进阶培训班-专题训练15

    杭电ACM-LCY算法进阶培训班-专题训练(03-07-11-15) 1012 最短路 #pragma GCC optimize(2) #pragma GCC optimize(3,"Ofa ...

  2. 杭电ACM-LCY算法进阶培训班-专题训练(矩阵快速幂)

    杭电ACM-LCY算法进阶培训班-专题训练(矩阵快速幂)[模板] 传送门 杭电ACM-LCY算法进阶培训班-专题训练(矩阵快速幂)[模板] 矩阵快速幂模板 Count Problem Descript ...

  3. 杭电ACM-LCY算法进阶培训班-专题训练(计算几何入门)

    杭电ACM-LCY算法进阶培训班-专题训练(计算几何入门) 传送门 杭电ACM-LCY算法进阶培训班-专题训练(计算几何入门) Shape of HDU Problem Description Inp ...

  4. 杭电ACM-LCY算法进阶培训班-专题训练(KMP)

    杭电ACM-LCY算法进阶培训班-专题训练(KMP) 杭电ACM-LCY算法进阶培训班-专题训练(KMP) 剪花布条 Problem Description Input Output Sample I ...

  5. 2021-06-18杭电ACM-LCY算法进阶培训班-专题训练16

    杭电ACM-LCY算法进阶培训班-专题训练(04-08-12-16) 1009 Intervals #pragma GCC optimize(2) #pragma GCC optimize(3,&qu ...

  6. 杭电ACM-LCY算法进阶培训班-专题训练09

    杭电ACM-LCY算法进阶培训班-专题训练09 1014 剪花布条 #pragma GCC optimize(2) #pragma GCC optimize(3,"Ofast",& ...

  7. 杭电ACM-LCY算法进阶培训班-专题训练(线段树)

    杭电ACM-LCY算法进阶培训班-专题训练(线段树) 传送门 目录 杭电ACM-LCY算法进阶培训班-专题训练(线段树) 张煊的金箍棒(2) Problem Description Input Out ...

  8. 【杭电ACM】1097 A hard puzzle

    [杭电ACM]1097  A hard puzzle http://acm.hdu.edu.cn/showproblem.php?pid=1097 先用int手写了算法结果竟然wrong answer ...

  9. 杭电ACM刷题(1):1002,A + B Problem II

    最近忙于考试复习,没有多少可供自己安排的时间,所以我利用复习之余的空闲时间去刷刷杭电acm的题目,也当对自己编程能力的锻炼吧. Problem Description I have a very si ...

最新文章

  1. MATLAB_10-模式识别_
  2. 1024程序员节 继续薅羊毛
  3. 20. C# -- Base, this 关键字
  4. 病毒 Worm.Logo.g
  5. android 反编译 dex2jar,Android反编译教程:apktool,dex2jar的使用
  6. 制定自己的SMART目标
  7. python将图片转换成手绘_利用Python生成手绘效果的图片
  8. HTML5+CSS3笔记 (黑马pink老师)
  9. 【优化求解】基于未来搜索算法FSA求解最优目标matlab代码
  10. SpringBoot设置网站页面小图标——Favicon
  11. 第7章 集成方法、随机森林
  12. SpringBoot启动报错:Failed to introspect Class [XXX] from ClassLoader
  13. linux读书摘要--正规表示法与文件格式化处理
  14. egg(一):创建一个egg项目
  15. 学习GAN必须阅读的10篇论文
  16. Python循环 - 胖子老板来包烟
  17. Daemontools简介
  18. Linux美化贴图!
  19. 基于springboot在线答疑系统
  20. PPT实用小技巧,让你的PPT炫酷起来!

热门文章

  1. 取原始数组中的指定数据push新数组
  2. 基于C++实现两个分数的加减法
  3. gensim实战01——word2vec
  4. ID3西瓜决策树python实现
  5. I2C接口简介和时序
  6. MLE的数值确定:Newton-Raphson迭代法、得分法
  7. N1盒子单臂路由设置
  8. 【计算机视觉】:(3)全景图像拼接
  9. java数据类型有哪几种_Java数据类型有哪些?Java数据类型包括几种?
  10. 【成为架构师课程系列】架构师的核心能力地图