三(四)元环
模拟赛考了这个东西,被创死了
其实总结下来就一个东西,如果我们给边定向,让度数小的向度数大的连,那所有点的出度不会超过\(\sqrt{m}\)
根号分治,如果本身的度数小于\(\sqrt{m}\),则明显合法,若大于了,则最多只有\(\sqrt{m}\) 个点的度数大于了当前点
一个三元环可以被拆成 \(A\rightarrow B\),\(A \rightarrow C\),$ B \rightarrow C$,那不妨枚举一个点周围所有的点,然后再枚举周围的点周围的点,如果被染色了,就可知有三元环存在
四元环就大同小异了,一个四元环定向之后的形态就两种
我们考虑在入度最多的点处统计答案,固定其对面的点,枚举其在原图上的边,再在这个点上枚举其定向边,加进答案统计就可以了
但这样会统计出事,因为对于第一张图,你从两边的点开始,也能统计出整个环,所以要求当起点的度数小于终点的度数时才能统计
signed main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
n=rd(),k=rd(),m=rd();
fp(i,1,m){
int x=rd(),y=rd()+n;
g[x].emplace_back(y),
g[y].emplace_back(x);
deg[x]++,deg[y]++;
}
iota(id+1,id+n+k+1,1);
sort(id+1,id+n+k+1,[](int x,int y){
return deg[x]<deg[y];
});
n+=k;
fp(i,1,n) rk[id[i]]=i;
fp(i,1,n)
for(int x:g[i])
if(rk[x]>=rk[i])
ng[i].emplace_back(x);
ll ans=0;
fp(i,1,n){
for(int x:g[i])
for(int y:ng[x])
if(rk[i]<rk[y])
ans+=ts[y]++;
for(int x:g[i])
for(int y:ng[x])
ts[y]=0;
}
cout << ans << endl;
return 0;
}
代码不是标准模板,仅供参考,慎重查看