标签:
D
分4种情况讨论
1 不需要加边 , 就是说原本就有一个奇数环,我们只要跑一次二分图就好了
2 加一条边 , 也就是说存在大于等于3个点的联通块 我们对于这个联通块也跑一遍二分图, 可以知道图中所有的 同颜色染色中的点任意相连,都是一个奇数环,那么对于每个联通分量都有相应的数可以计算
3 加两条边,也就是说没有大于两个点的联通块存在,并且有两个点的联通块存在,答案也是可以计算出来的 e*(n-2)
4 加三条边 那么就可以知道每个联通块只有一个点,答案是 n*(n-1)*(n-2)/6;
#include <iostream> #include <algorithm> #include <string.h> #include <cstdio> #include <vector> using namespace std; const int maxn=100005; typedef long long LL; int fa[maxn],Enum[maxn]; pair<int,int>e[maxn]; int fin(int a) { return fa[a]=(a==fa[a])?a:fin( fa[a] ); } bool solve1(LL n,int m) { for(int i=0; i<m; i++) { int a=e[i].first,b=e[i].second; a=fin(a); b=fin(b); if(a==b)continue; Enum[a]+=Enum[b]; fa[b]=a; } LL num1=0,num2=0; for(int i=1; i<=n; i++) { if(fa[i]!=i)continue; if(Enum[i]>2)return false; if(Enum[i]==1)num1++; else num2++; } if(num2==0){ LL d=n*(n-1)*(n-2)/6; printf("3 %I64d\n",d); }else{ LL d=num2*(n-2); printf("2 %I64d\n",d); } return true; } int H[maxn],nx[maxn*2],to[maxn*2],numofedg; void add(int a, int b){ numofedg++; to[numofedg]=b; nx[numofedg]=H[a]; H[a]=numofedg; numofedg++; to[numofedg]=a; nx[numofedg]=H[b]; H[b]=numofedg; } int color[maxn],num1,num2; bool bipartite(int u) { if(color[u]==1)num1++; else num2++; for(int i=H[u]; i; i=nx[i]) { int v=to[i]; if(color[u]==color[v])return false; if(color[v]==0){ color[v]=3-color[u]; if(bipartite(v)==false)return false; } } return true; } void solve2(LL n, int m) { for(int i=0; i<m; i++){ add(e[i].first,e[i].second); } LL ans=0; memset(color,0,sizeof(color)); for(int i=1; i<=n; i++) { if(color[i]==0){ color[i]=1; num1=num2=0; if(bipartite(i)==false){ printf("0 1\n");return ; }else{ ans+= 1LL*num1*(num1-1)/2 +1LL*num2*(num2-1)/2; } } } printf("1 %I64d\n",ans); } int main() { int n,m; scanf("%d%d",&n,&m); numofedg=0; for(int i=1; i<=n; i++){fa[i]=i,Enum[i]=1; H[i]=0; } for(int i=0; i<m; i++) { scanf("%d%d",&e[i].first,&e[i].second); } if(solve1(n,m)){return 0;} solve2(n,m); return 0; }
1
Codeforces Round #311 (Div. 2)
标签:
原文地址:http://www.cnblogs.com/Opaser/p/4811720.html