After reading the report, the idea is the same. I just need to paste it.
After adding an edge, the graph can be divided into two parts X and Y. Only the side from X to Y has no edge from Y to X, so we need to make the number of sides as much as possible, the X part must be a complete graph, and the Y part is also. At the same time, each vertex in the X part has an edge. Assume that the X part has x points, Y has y points, x + y = n, and the number of edge F = x * y + x * (x-1) + y * (Y-1), sorted out: F = N * N-x * y. When x + y is set, the closer the two are, the greater x * y, the maximum number of edges, therefore, the gap between the number of points in Part X and part Y will be larger. Therefore, first, for the given digraph contraction point, for each point after the contraction point, if its degree of exit or entry is 0, it may become X or Y. Therefore, only the exit degree after the contraction or the entry degree is 0, the vertex that contains the least number of nodes makes it a part. All other vertices add up to another part to get the graph with the maximum number of edges.
//109MS 2916KB#include <stdio.h>#include <string.h>#define LL long longconst int M = 100005;const int inf = 0x3f3f3f3f;struct Edge{ int to,nxt;} edge[M];int head[M],low[M],dfn[M],stack[M+10];int vis[M],out[M],in[M],belong[M];int scc,cnt ,top,ep;LL n,m;int min (int a,int b){ return a > b ? b : a;}void addedge (int cu,int cv){ edge[ep].to = cv; edge[ep].nxt = head[cu]; head[cu] = ep ++;}void Tarjan(int u){ int v; dfn[u] = low[u] = ++cnt; stack[top++] = u; vis[u] = 1; for (int i = head[u]; i != -1; i = edge[i].nxt) { v = edge[i].to; if (!dfn[v]) { Tarjan(v); low[u] = min(low[u],low[v]); } else if (vis[v]) low[u] = min(low[u],dfn[v]); } if (dfn[u] == low[u]) { ++scc; do { v = stack[--top]; vis[v] = 0; belong[v] = scc; } while (u != v); }}void solve(){ int u,v; scc = top = cnt = 0; memset (vis,0,sizeof(vis)); memset (dfn,0,sizeof(dfn)); memset (out,0,sizeof(out)); memset (in,0,sizeof(in)); for (u = 1; u <= n; u ++) if (!dfn[u]) Tarjan(u); for (u = 1; u <= n; u ++) { for (int i = head[u]; i != -1; i =edge[i].nxt) { v = edge[i].to; if (belong[u] != belong[v]) { out[belong[u]] ++; in[belong[v]] ++; } } } int num[M],Min; memset (num,0,sizeof(num)); for (u = 1; u <= n; u ++) if (!in[belong[u]]) num[belong[u]] ++; for (u = 1; u <= scc; u ++) if (num[u]!= 0&&num[u]<Min) Min = num[u]; memset (num,0,sizeof(num)); for (u = 1; u <= n; u ++) if (!out[belong[u]]) num[belong[u]] ++; for (u = 1; u <= scc; u ++) if (num[u]!= 0&&num[u]<Min) Min = num[u]; if (scc == 1) { printf ("-1\n"); return ; } LL ans = n*(n-1)-Min*(n-Min) - m; printf ("%I64d\n",ans);}int main (){#ifdef LOCAL freopen("in.txt","r",stdin);#endif int T,u,v,cnt = 0; scanf ("%d",&T); while (T --) { scanf ("%I64d%I64d",&n,&m); ep = 0; memset (head,-1,sizeof(head)); for (int i = 0; i < m; i++) { scanf ("%d%d",&u,&v); addedge(u,v); } printf ("Case %d: ",++cnt); solve(); } return 0;}