刷题总结——date(ssoj)
题目:
题目背景
SOURCE:NOIP2015-SHY-9
题目描述
小Y和小Z好不容易有机会相见啦,可是邪恶的小H却不想让他们相见。现在有一些城市,城市之间有双向路径相连,有路径相连的城市之间可以互相到达。小H可以任意选择一条路径,然后用他的邪恶力量污染这条路径,使得它不能被通行。虽然小Y和小Z在千辛万苦之后相遇了,但小Y非常害怕。她想让小Z告诉她,他们初始在哪些点对上,小H就可以选择一条路径污染使得他们不能相见。
注意:如果有一对点之间初始的时候就不联通,也是满足条件的,需要输出这对点。这是因为本来不联通,那么删一条边,当然也不联通。
输入格式
第一行两个数字 N 和 M 。N 表示城市数,M 表示路径数。
第二行到第 M+1 行,两个数 a 和 b。其中 1≤a,b≤N ,表示 a 和 b 之间有路径相连。
输出格式
输出一个整数,表示所求点对的数量
样例数据 1
备注
【样例说明】
点对(1,2)满足不能相见的条件。
【数据范围】
对 30% 的输入数据 :1≤N≤100,1≤M≤200
对 100% 的输入数据 :1≤N≤20000,1≤M≤40000
题解:
就是求每个边双连通分量···然后双连通分量内的点肯定是可以相互到达的,因此我们先算出所有的点对··再减去所有双连通分量中的点对数量(都是合法点对)即可···
另外注意处理重边以及断点的情况······md图论每次都被这两东西坑···
代码:
#include<iostream> #include<cstdio> #include<cstdlib> #include<cmath> #include<ctime> #include<cctype> #include<cstring> #include<string> #include<algorithm> using namespace std; const int N=2e4+5; const int M=4e4+5; int first[N],next[M*2],go[M*2],tot=1; int n,m,dfn[N],low[N],cnt=0; int totgroup,size[N]; bool tag[M*2],visit[N]; long long ans=0; inline int R() { char c;int f=0; for(c=getchar();c<'0'||c>'9';c=getchar()); for(;c<='9'&&c>='0';c=getchar()) f=(f<<3)+(f<<1)+c-'0'; return f; } inline void comb(int a,int b) { next[++tot]=first[a],first[a]=tot,go[tot]=b; next[++tot]=first[b],first[b]=tot,go[tot]=a; } inline void tarjan(int u,int pre) { dfn[u]=low[u]=++cnt; for(int e=first[u];e;e=next[e]) { int v=go[e]; if(!dfn[v]) { tarjan(v,e);low[u]=min(low[u],low[v]); if(dfn[u]<low[v]) tag[e]=tag[e^1]=true; } else if((e^1)!=pre) low[u]=min(low[u],dfn[v]); } } inline void dfs(int u,int pre) { size[totgroup]++;visit[u]=true; for(int e=first[u];e;e=next[e]) { if(!tag[e]&&(e^1)!=pre&&!visit[go[e]]) { int v=go[e];dfs(v,e); } } } int main() { //freopen("a.in","r",stdin); n=R(),m=R();int a,b; for(int i=1;i<=m;i++) { a=R(),b=R(); comb(a,b); } for(int i=1;i<=n;i++) if(!dfn[i]) tarjan(i,-1); for(int i=1;i<=n;i++) { if(!visit[i]) totgroup++,dfs(i,-1); } ans=(long long)n*(n-1)/2; for(int i=1;i<=totgroup;i++) ans-=(long long)size[i]*(size[i]-1)/2; cout<<ans<<endl; return 0; }