题目描述
你是活跃在历史幕后的一名特工,为了世界和平而夜以继日地努力着。
这个世界有N个国家,编号为1..N;
你的目的是在这N个国家之间建立尽可能多的友好关系。
你为了制定一个特工工作的计划,作出了一张当今国际关系的示意图。
你准备了一张非常大的画纸,先画下了代表每个国家的N个点。
接下来,为了表示现在的国际关系,画下了M个连接两个国家的有向边;
其中从国家u连向国家v的有向边,表示国家u向国家v派遣了大使,下文称作边(u,v)。
这样就做出了N个点M条边的当今国际关系示意图。
作为两国友好关系的开端,两国之间需要进行「友好条约缔结会议」,以下简称会议。
如果某两个国家p和q要进行会议,那么需要一个向两国都派遣了大使的国家x作为中介。
会议结束后,会议的双方相互向对方的国家派遣大使。
换句话说,为了让国家p和国家q进行会议,必须存在一个国家x满足边(x,p)和边(x,q)都存在;
并且在会议后添加两条边(p,q)和(q,p)(如果需要添加的某条边已经存在则不添加)。
你的工作是对于可以进行会议的两国,选择会议的中介并促使会议进行。
使用这张图进行工作的模拟的话,世界距离和平还有多远的一个重要的基准就是这张图上的边数。
现在给出国家的个数以及当今国际关系的情报,请你求出反复选择两个国家,促使它们进行会议后,图上最多会有多少条边。
输入
第一行两个空格分隔的整数N和M,分别表示世界上国家的个数和图中的边数。
接下来M行描述画纸上的有向边的信息,其中第i行有两个空格分隔的整数ai和bi,表示图中有一条从ai到bi的有向边。
输出
输出一行一个整数,表示能实现的边数的最大值。
注意这个边数包括原有的边数和新连接的边数。
样例输入 5 4 1 2 1 3 4 3 4 5 样例输出 10 样例解释 国家1作为中介国,国家2与3开会。 国家4作为中介国,国家3与5开会。 国家3作为中介国,国家2与5开会。
数据范围:1≤N≤105,1≤M≤2×105,1≤ai,bi≤N,ai≠bi,(ai,bi)≠(aj,bj)
参考资料:
[1]:http://icpc.upc.edu.cn/blog/?p=108
题意(摘抄自[1]):
如果存在有向边<a,b>和<a,c>,就添加两条有向边<b,c>和<c,b>(已经存在就不添加),问最多有多少条边;
题解:
昨天比赛做这道题的时候,想到了SCC,但我真的用SCC了,中间过程处理的不好(代码写搓了,逃)........
扫描二维码关注公众号,回复:
6303988 查看本文章
今天晚上补这道题,看了看题解,和昨天自己想的差不多,就是代码实现上,[1]并没有用SCC知识用SCC思考这道题的做法;
哎,欠缺的还是太多了,理解了将近半个小时,终于理解了,tql;
下面谈谈我的进一步理解:
(看会专业课先,理解明天写,下周要考两门,orz)
AC代码(偷偷换成了我的风格):
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define ll long long 4 #define mem(a,b) memset(a,b,sizeof(a)) 5 const int maxn=1e5+50; 6 7 int n,m; 8 int num; 9 int head[maxn]; 10 struct Edge 11 { 12 int to; 13 int next; 14 }G[maxn<<1]; 15 void addEdge(int u,int v) 16 { 17 G[num]={v,head[u]}; 18 head[u]=num++; 19 } 20 ll tot[maxn]; 21 int fa[maxn]; 22 int Find(int x) 23 { 24 return fa[x] == -1 ? x:fa[x]=Find(fa[x]); 25 } 26 void DFS(int u,int x) 27 { 28 for(int i=head[u];~i;i=G[i].next) 29 { 30 int y=G[i].to; 31 x=Find(x); 32 y=Find(y); 33 34 if(x == y) 35 continue; 36 37 fa[y]=x; 38 tot[x] += tot[y]; 39 DFS(y,x); 40 } 41 } 42 ll Solve() 43 { 44 bool update=true; 45 while(update) 46 { 47 update=false; 48 for(int u=1;u <= n;++u) 49 { 50 int x=tot[Find(u)] == 1 ? -1:u; 51 for(int i=head[u];~i;i=G[i].next) 52 { 53 int y=G[i].to; 54 if(x == -1) 55 x=y; 56 else 57 { 58 x=Find(x); 59 y=Find(y); 60 if(x == y) 61 continue; 62 fa[y]=x; 63 tot[x] += tot[y]; 64 DFS(y,x); 65 update=true; 66 } 67 } 68 } 69 } 70 ll ans=0; 71 for(int u=1;u <= n;++u) 72 { 73 if(fa[u] != -1) 74 continue; 75 76 ans += tot[u]*(tot[u]-1); 77 for(int i=head[u];~i;i=G[i].next) 78 { 79 int x=Find(u); 80 int y=Find(G[i].to); 81 82 if(x != y) 83 ans++; 84 } 85 } 86 return ans; 87 } 88 void Init() 89 { 90 num=0; 91 for(int i=0;i <= n;++i) 92 head[i]=-1; 93 for(int i=0;i <= n;++i) 94 tot[i]=1,fa[i]=-1; 95 } 96 int main() 97 { 98 scanf("%d%d",&n,&m); 99 Init(); 100 for(int i=1;i <= m;++i) 101 { 102 int u,v; 103 scanf("%d%d",&u,&v); 104 addEdge(u,v); 105 } 106 printf("%lld\n",Solve()); 107 108 return 0; 109 }