CF475E Strongly Connected City 2 题解

题目链接:CF475E Strongly Connected City 2

首先边双之内是可以有方法定向使其变成任意两个点之间都可达的,证明感性理解。将边双缩完点后图变为一棵树,观察可得最优点一定是带权重心,有些子树连向他然后他连向剩下的子树,子树内的连边方向和子树的根和重心的连边一样。这样是最接近 $ frac{n^2}{4} $ 的。

代码:

#include<bits/stdc++.h>
#define time(null) chrono::steady_clock::now().time_since_epoch().count()
#define int long long
#define uint unsigned long long
#define debug() cout<<"come here\n"
#define INF 0x3f3f3f3f3f3f3f3f
#define pii pair<int,int>
#define pb push_back
#define Code return
#define by 0
#define MCYYDS ;
using namespace std;
int qpow(int a,int b,int p=INF){int ret=1;while(b){if(b&1)ret=(ret*a)%p;a=(a*a)%p;b>>=1;}return ret;}
inline int read(){int ret=0,f=1;char ch=getchar();while(ch<'0'||ch>'9')f=(ch=='-'?-1:f),ch=getchar();while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+(ch^48),ch=getchar();return ret*f;}
inline void write(int x){if(x<0){putchar('-');write(-x);return ;}if(x>9)write(x/10);putchar((char)(x%10+48));}
inline void writech(int x,char ch){write(x);putchar(ch);}
int dfn[2005],low[2005],sz[2005],col[2005],s[2005],tot,cnt,sum,cur;
vector<int> e[2005],g[2005];
bitset<2005> dp;
stack<int> stk;
void dfs(int u,int fa)
{
	dfn[u]=low[u]=++tot;
	stk.push(u);
	for(auto v:e[u])
	{
		if(v==fa)continue;
		if(!dfn[v])
		{
			dfs(v,u);
			low[u]=min(low[u],low[v]);
		}
		else low[u]=min(low[u],dfn[v]);
	}
	if(dfn[u]==low[u])
	{
		++cnt;
		while(stk.size()&&stk.top()!=u)
		{
			s[cnt]++;
			col[stk.top()]=cnt;
			stk.pop();
		}
		s[cnt]++;
		col[stk.top()]=cnt;
		stk.pop();
		sum+=s[cnt]*s[cnt]; 
	}
}
void dfs2(int u,int fa)
{
	sz[u]=s[u];
	for(auto v:g[u])
	{
		if(v==fa)continue;
		dfs2(v,u);
		sz[u]+=sz[v];
	}
	cur+=s[u]*(sz[u]-s[u]);
}
signed main()
{
//	ios::sync_with_stdio(0);
//	cin.tie(0);
//	cout.tie(0);
	int n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		int u=read(),v=read();
		e[u].pb(v);
		e[v].pb(u);
	}
	for(int i=1;i<=n;i++)
	{
		if(!dfn[i])dfs(i,0);
	}
	for(int i=1;i<=n;i++)
	{
		for(auto v:e[i])
		{
			if(col[i]!=col[v])
			{
				g[col[i]].pb(col[v]);
			}
		}
	}
	int ans=0;
	for(int i=1;i<=cnt;i++)
	{
		memset(sz,0,sizeof(sz));
		cur=0;
		dfs2(i,0);
		dp.reset();
		dp[0]=1;
		for(auto v:g[i])
		{
			dp|=(dp<<sz[v]);
		}
		for(int j=(sz[i]-s[i])/2;j>=0;j--)
		{
			if(dp[j])
			{
				cur+=j*(n-j-s[i]);
				break;
			}
		}
		ans=max(ans,cur); 
	}
	writech(ans+sum,'\n');
	Code by MCYYDS
}

posted @ 2026-07-14 14:46  MCYYDS  阅读(4)  评论(0)    收藏  举报