[CF475E]Strongly Connected City 2
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[CF475E]Strongly Connected City 2相关的知识,希望对你有一定的参考价值。
题意:给一个无向图,你需要给所有边定向,使定向之后存在最多的点对$(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的主要内容,如果未能解决你的问题,请参考以下文章
Dynamic V Strongly Typed Views
algorithm@ Strongly Connected Component
PTA Strongly Connected Components