标签:连通 ch sum 节点 Blockade ans ll
题目描述
给出一张n个点、m条边的无向连通图,输出n个数,分别代表删去第i个点后有多少点对不能互通。
思路
实质上,如果一个点不是割点,那么删除这个点无法使任何点对无法在连通,所以直接输出n-1。如果这个点是割点,那么显然会把原图分为几个连通块,我们只要求出这几个连通块中的节点数就可以统计答案了。我们记每个点的答案为ans[i],那么当我们进行tarjan(u)时,如果判断了这个点是割点,假设sum为之前其它的点双联通分量的节点数,当又出现一个点双联通分量时,设它的节点数为cnt,那么显然答案就需要增加sum*cnt,再把cnt累加到sum中。而如果结束对所有u连接的点进行访问后,n-sum-1的点也形成一个点双联通分量(即在u上方的节点),累加答案。最后我们再加上删除这个点会使这个点和其他n-1个点不再连通的数量。而题目中说明点对有顺序,所以要乘2。
代码
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll N=1e5+10,M=1e6+10; ll read() { ll res=0,w=1; char ch=getchar(); while(!isdigit(ch)){if(ch=='-')w=-1;ch=getchar();} while(isdigit(ch))res=(res<<3)+(res<<1)+(ch^48),ch=getchar(); return res*w; } ll head[N],tot,to[M],nxt[M]; void add_edge(ll x,ll y) { nxt[++tot]=head[x]; head[x]=tot; to[tot]=y; } ll dfn[N],low[N],idx,root; ll ans[N],siz[N],n; void tarjan(ll u) { dfn[u]=low[u]=++idx; siz[u]=1; ll sum=0,cnt=0; for(ll i=head[u];i;i=nxt[i]) { ll v=to[i]; if(!dfn[v]) { cnt++; tarjan(v); siz[u]+=siz[v]; low[u]=min(low[u],low[v]); if((u==root&&cnt>1)||(u!=root&&low[v]>=dfn[u])) { ans[u]+=sum*siz[v]; sum+=siz[v]; } } else low[u]=min(low[u],dfn[v]); } ans[u]+=sum*(n-sum-1); ans[u]=(ans[u]+n-1)<<1; } int main() { n=read(); ll m=read(); for(ll i=1;i<=m;i++) { ll x=read(),y=read(); add_edge(x,y);add_edge(y,x); } root=1; tarjan(1); for(ll i=1;i<=n;i++) printf("%lld\n",ans[i]); }
标签:连通,ch,sum,节点,Blockade,ans,ll
来源: https://www.cnblogs.com/fangbozhen/p/11747317.html
本站声明:
1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。