Tarjan Algorithm
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.
I feel so bad... The game lasted for WA and later found that the initialization error was forgotten ..
#include<iostream>#include<cstdio>#include<cstring>using namespace std;#define maxm 210000#define maxn 210000#define LL __int64LL n,m;LL head[maxn],cnt;LL v[maxm],next[maxm];LL dfn[maxn],low[maxn],step;LL sta[maxn],top;LL ID[maxn],IdNum;LL d_in[maxn],d_out[maxn];bool vis[maxn];LL sum[maxn];void add(LL a,LL b){v[cnt]=b;next[cnt]=head[a];head[a]=cnt++;}void Init(){memset(sum,0,sizeof(sum));memset(vis,0,sizeof(vis));memset(d_in,0,sizeof(d_in));memset(d_out,0,sizeof(d_out));memset(head,-1,sizeof(head));memset(dfn,0,sizeof(dfn));memset(low,0,sizeof(low));IdNum=top=step=cnt=0;}void tarjan(LL u){low[u]=dfn[u]=++step;sta[++top]=u;vis[u]=1;for(LL i=head[u];~i;i=next[i]){LL to=v[i];if(!dfn[to]){tarjan(to);low[u]=min(low[u],low[to]);}elseif(vis[to])low[u]=min(low[u],dfn[to]);}if(low[u]==dfn[u]){LL x;IdNum++;do{x=sta[top--];vis[x]=0;sum[IdNum]++;ID[x]=IdNum;}while(u!=x);}}void build(){for(LL i=1;i<=n;i++)for(LL j=head[i];~j;j=next[j]){LL to=v[j];if(ID[i]!=ID[to]){d_in[ID[to]]++;d_out[ID[i]]++;}}}LL max(LL a,LL b){if(a>b)return a;return b;}int main(){LL x,y;LL t;int cnt=0;cin>>t;while(t--){scanf("%I64d%I64d",&n,&m);if(n==1){printf("Case %d: -1\n",++cnt);continue;}Init();for(LL i=1;i<=m;i++){scanf("%I64d%I64d",&x,&y);add(x,y);}for(LL i=1;i<=n;i++)if(!dfn[i])tarjan(i);build();LL ans=0;LL k;for(LL i=1;i<=IdNum;i++)if(d_in[i]==0||d_out[i]==0){k=sum[i];ans=max(ans,k*(k-1)+(n-k)*(n-k-1)+k*(n-k)-m);}if(IdNum!=1)printf("Case %d: %I64d\n",++cnt,ans);elseprintf("Case %d: -1\n",++cnt);}return 0;}