题解:CF1651E Sum of Matchings
yingkeqian9217 · · 题解
提供一种比较好写的小常数做法。
注意到原图由若干偶环组成,容易想到对于每个环计算其贡献。设环长为
这里已经可以通过枚举链并确定链端点不取的方式直接精确计算每条链的贡献了,但是这样太麻烦了,有没有更简洁的做法呢?注意到确定链被包含比链恰好是极长的简单,这类问题我们都可以考虑容斥。
事实上,我们只要令一条长为
时间复杂度
#include<bits/stdc++.h>
#define maxn 110005
typedef long long ll;
using namespace std;
const int inf=2e9+7;
int n,vis[maxn];
vector<int>e[maxn],vec;
void dfs(int x){
vec.push_back(x);
vis[x]=1;
for(int i:e[x]) if(!vis[i]) dfs(i);
}
int main(){
ll ans=0;
scanf("%d",&n);
for(int i=1,u,v;i<=n+n;i++) scanf("%d%d",&u,&v),e[u].push_back(v),e[v].push_back(u);
for(int i=1;i<=n+n;i++){
if(vis[i]) continue;
vec.clear();
dfs(i);
// assert(vec.size()%2==0);
int m=(vec.size()>>1);
for(int i=0;i<m+m;i++){
int min1=inf,max1=-inf,min2=inf,max2=-inf;
for(int j=0;j<m+m-1;j++){
int id=vec[(i+j)%(m+m)];
if(id<=n) min1=min(min1,id),max1=max(max1,id);
else min2=min(min2,id-n),max2=max(max2,id-n);
if(!j) continue;
ans+=(ll)(j&1?1:-1)*min1*(n-max1+1)*min2*(n-max2+1);
}
if(!i) ans-=(ll)m*min1*(n-max1+1)*min2*(n-max2+1);
}
}
printf("%lld\n",ans);
}