传送门
题目描述
总共有n个节点,m条路径,要求其中m-2条路径走两遍,剩下2条路径仅走一遍,问不同的路径总数有多少,如果仅走一遍的两条边不同则将这两条路径视为不同。
分析
把每一条边复制一遍,然后删去两条边要求构成欧拉路。
根据欧拉路的性质可以知道这两条边必然连在同一个点上
但是同时还需要考虑自环的影响
如果两条边连在同一个点上,那么对答案的影响就是
d[i] * (d[i] - 1) / 2;
d表示每个点除自环外的度数
如果两条边全部都是自环,那么对答案的影响就是
cnt * (cnt - 1) / 2;
如果选一个自环,一条边的话,对答案的影响就是
cnt * (m - cnt);
代码
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define debug(x) cout<<#x<<":"<<x<<endl;
#define dl(x) printf("%lld\n",x);
#define di(x) printf("%d\n",x);
#define _CRT_SECURE_NO_WARNINGS
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;
const ll mod= 1000000007;
const double eps = 1e-9;
const double PI = acos(-1);
template<typename T>inline void read(T &a){char c=getchar();T x=0,f=1;while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}a=f*x;}
int n,m;
int q[N];
bool st[N];
ll d[N];
int find(int x){
if(x != q[x]) q[x] = find(q[x]);
return q[x];
}
int main(){
read(n),read(m);
int p = -1;
ll cnt = 0; //自环数量
for(int i = 1;i <= n;i++) q[i] = i;
for(int i = 1;i <= m;i++){
int x,y;
read(x),read(y);
st[x] = 1,st[y] = 1;
if(x == y){
cnt++;
continue;
}
p = x;
d[x]++,d[y]++;
x = find(x);
y = find(y);
q[x] = y;
}
for(int i = 1;i <= n;i++){
if(!st[i]) continue;
if(find(i) != find(p)){
puts("0");
return 0;
}
}
ll ans = 0;
for(int i = 1;i <= n;i++) ans += (d[i] - 1) * d[i] / 2;
ans += cnt * (cnt - 1) / 2;
ans += cnt * (m - cnt);
dl(ans);
return 0;
}
/**
* ┏┓ ┏┓+ +
* ┏┛┻━━━┛┻┓ + +
* ┃ ┃
* ┃ ━ ┃ ++ + + +
* ████━████+
* ◥██◤ ◥██◤ +
* ┃ ┻ ┃
* ┃ ┃ + +
* ┗━┓ ┏━┛
* ┃ ┃ + + + +Code is far away from
* ┃ ┃ + bug with the animal protecting
* ┃ ┗━━━┓ 神兽保佑,代码无bug
* ┃ ┣┓
* ┃ ┏┛
* ┗┓┓┏━┳┓┏┛ + + + +
* ┃┫┫ ┃┫┫
* ┗┻┛ ┗┻┛+ + + +
*/