码迷,mamicode.com
首页 > 其他好文 > 详细

[CF475E]Strongly Connected City 2

时间:2017-11-27 23:33:31      阅读:174      评论:0      收藏:0      [点我收藏+]

标签:题意   alt   http   log   string   can   scanf   city   图片   

题意:给一个无向图,你需要给所有边定向,使定向之后存在最多的点对$(a,b)$使得从$a$能到$b$

 

这个题,真的是太妙啦!

首先,给一个边双联通分量定向之后,它可以变成一个强联通分量,所以我们显然要把每个双联通分量缩点,然后处理树上的问题

那么答案分为两部分,一部分是双联通分量内部的,一个是树上的

设某双联通分量的大小为$k$,因为给它定向之后里面的点两两可以互达,所以它对答案的贡献为$k^2$

接下来找树上的,有一个结论说,最优解一定长这样:存在一个点$s$,使得对于任意其他点$t$,要么$s$可以到$t$,要么$t$可以到$s$,我们把$s$作为根使整棵树成为有根树

感觉上是对的没错我不会证

出题人这样说:

技术分享图片

这种玄学的东西真是令人不知所措......

回归正题,有了这个结论,我们可以知道,$s$的每一个子树内的边要么都朝向$s$,要么都是远离$s$的方向

我们可以枚举根

记$s_i$为编号为$i$的双联通分量的大小,$siz_i$记以$i$为根的子树大小

那么每个节点$i$的子树内贡献的答案就是$s_i\cdot(siz_i-s_i)$

所以最后我们还得统计一下过根的答案,也就是决定连着根的那些边的朝向

假设朝向根的节点的$siz$总和为$p$,那么过根的答案就是$p\cdot(n-s_i-p)$

所以我们要做的就是把根的子树分成尽可能平均的两部分,直接上背包就好了

然后,终于做完了......

#include<stdio.h>
#include<string.h>
struct gedge{
	int to,nex;
	bool bri;
}ge[4000010];
struct tedge{
	int to,nex;
}te[4010];
int gh[2010],th[2010],s[2010],siz[2010],dfn[2010],low[2010],col[2010],q[2010],f[2010],tot,m;
void gadd(int a,int b){
	tot++;
	ge[tot].to=b;
	ge[tot].nex=gh[a];
	gh[a]=tot;
	ge[tot+m].to=a;
	ge[tot+m].nex=gh[b];
	gh[b]=tot+m;
}
void tadd(int a,int b){
	tot++;
	te[tot].to=b;
	te[tot].nex=th[a];
	th[a]=tot;
}
int min(int a,int b){return a<b?a:b;}
int max(int a,int b){return a>b?a:b;}
void bri(int x){
	ge[x].bri=1;
	if(x>m)
		ge[x-m].bri=1;
	else
		ge[x+m].bri=1;
}
void tarjan(int fa,int x){
	tot++;
	dfn[x]=low[x]=tot;
	for(int i=gh[x];i;i=ge[i].nex){
		if(dfn[ge[i].to]==0){
			tarjan(x,ge[i].to);
			low[x]=min(low[x],low[ge[i].to]);
			if(low[ge[i].to]>dfn[x])bri(i);
		}else if(dfn[ge[i].to]<dfn[x]&&ge[i].to!=fa)
			low[x]=min(low[x],dfn[ge[i].to]);
	}
}
void dfs(int x){
	for(int i=gh[x];i;i=ge[i].nex){
		if(col[ge[i].to]){
			if(col[ge[i].to]!=col[x]){
				tadd(col[x],col[ge[i].to]);
				tadd(col[ge[i].to],col[x]);
			}
		}else if(!ge[i].bri){
			col[ge[i].to]=col[x];
			dfs(ge[i].to);
		}
	}
}
void dfs(int fa,int x){
	siz[x]=s[x];
	for(int i=th[x];i;i=te[i].nex){
		if(te[i].to!=fa){
			dfs(x,te[i].to);
			siz[x]+=siz[te[i].to];
		}
	}
}
int main(){
	int N,n,i,j,k,a,b,ans,res;
	scanf("%d%d",&n,&m);
	for(i=0;i<m;i++){
		scanf("%d%d",&a,&b);
		gadd(a,b);
	}
	tot=0;
	tarjan(0,1);
	N=0;
	tot=0;
	for(i=1;i<=n;i++){
		if(col[i]==0){
			N++;
			col[i]=N;
			dfs(i);
		}
	}
	for(i=1;i<=n;i++)s[col[i]]++;
	ans=0;
	for(i=1;i<=N;i++){
		dfs(0,i);
		res=0;
		for(j=1;j<=N;j++)res+=s[j]*siz[j];
		q[0]=0;
		for(j=th[i];j;j=te[j].nex){
			q[0]++;
			q[q[0]]=te[j].to;
		}
		memset(f,0,sizeof(f));
		for(j=1;j<=q[0];j++){
			for(k=n-s[i];k>=siz[q[j]];k--)f[k]=max(f[k],f[k-siz[q[j]]]+siz[q[j]]);
		}
		res+=f[(n-s[i])>>1]*(n-s[i]-f[(n-s[i])>>1]);
		ans=max(ans,res);
	}
	printf("%d",ans);
}

[CF475E]Strongly Connected City 2

标签:题意   alt   http   log   string   can   scanf   city   图片   

原文地址:http://www.cnblogs.com/jefflyy/p/7905970.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!