NOIP模拟 星星 【图论】

来源:互联网 发布:中信证券网上交易软件 编辑:程序博客网 时间:2024/05/29 14:33

题目大意:

给定一个无重边自环的无向图,问图中有多少对共边三元环。如:
这里写图片描述
(n,m100000)。

解题思路:

最朴素的思路是枚举每一条边看它在多少个三元环内,也就是该边两端点所连相同点的个数,设为cnt,那么就会产生C2cnt个共边三元环。这样的复杂度是O(nm)的。

但我们对于每个点,可以先把它连的点打上标记,再枚举所有与它相连且度比它小的点的边集来求每条边的贡献,可以证明这样的复杂度是O(mm)的。

考虑把点按度是否大于m分为重轻点,那所有边可分为三种:
1.轻点连轻点:有O(m)条,但每个轻点的边集只有O(m),总复杂度为O(mm)。
2.重点连轻点:也有O(m)条,但会枚举轻点的边集,只有O(m),总复杂度也为O(mm)。
3.重点连重点:处理对于一个重点最多涉及O(m)条边,而共有O(m)个重点,总复杂度也为O(mm)。

#include<iostream>#include<cstdio>#include<cstring>#include<string>#include<algorithm>#include<cmath>#include<vector>#include<queue>#define ll unsigned long longusing namespace std;int getint(){    int i=0,f=1;char c;    for(c=getchar();(c<'0'||c>'9')&&c!='-';c=getchar());    if(c=='-')f=-1,c=getchar();    for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';    return i*f;}const int N=100005,M=400005;int T,n,m,du[N],visit[N];int tot,first[N],nxt[M],to[M];ll ans;void add(int x,int y){    nxt[++tot]=first[x],first[x]=tot,to[tot]=y,du[y]++;}void solve(int u){    //memset(visit,0,sizeof(visit));    for(int e=first[u];e;e=nxt[e])visit[to[e]]=u;    for(int e=first[u];e;e=nxt[e])    {        int v=to[e];        if(du[v]<=du[u])        {            if(du[v]==du[u]&&v>u)continue;            int cnt=0;            for(int i=first[v];i;i=nxt[i])                if(visit[to[i]]==u)cnt++;            ans+=1ll*cnt*(cnt-1)/2;        }    }}int main(){    //freopen("star.in","r",stdin);    //freopen("star.out","w",stdout);    int x,y;    T=getint();    while(T--)    {        ans=tot=0;        memset(first,0,sizeof(first));        memset(du,0,sizeof(du));        memset(visit,0,sizeof(visit));        n=getint(),m=getint();        while(m--)        {            x=getint(),y=getint();            add(x,y),add(y,x);        }        for(int i=1;i<=n;i++)            solve(i);        cout<<ans<<'\n';    }    return 0;}
原创粉丝点击