题目大意
给定一个
n
个点,
1≤n≤5×104,1≤m≤105
题目分析
首先我们要知道一个性质:任何一个点,与其直接相连的度数大于等于它的点最多只有
2m−−−√
个。
证明:设有
x
个这样的点,这个点度数至少为
考虑将所有点按照度数先排一个序,令点
x
的排名为
考虑这样一个四元环,我们假设B
B
是四个点中
考虑枚举点
枚举完
A
之后,我们用和枚举时一样的方法来清空计数器就好了。
枚举y
代码实现
#include <algorithm>
#include <iostream>
#include <cstdio>
#include <cctype>
using namespace std;
typedef long long LL;
int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
const int N=50005;
const int M=100005;
const int E=M<<1;
const int B=500;
int deg[N],kth[N],rank[N],cnt[N];
int tov[E],nxt[E];
int key[N][B];
int last[N];
int n,m,tot;
LL ans;
bool cmp(int x,int y){return deg[x]<deg[y];}
void insert(int x,int y){tov[++tot]=y,nxt[tot]=last[x],last[x]=tot;}
void pre()
{
for (int i=1;i<=n;++i) kth[i]=i;
sort(kth+1,kth+1+n,cmp);
for (int i=1;i<=n;++i) rank[kth[i]]=i;
for (int x=1;x<=n;++x)
for (int i=last[x],y;i;i=nxt[i])
if (rank[y=tov[i]]>rank[x]) key[x][++key[x][0]]=y;
}
void calc()
{
for (int x=1;x<=n;++x)
{
for (int i=last[x],y;i;i=nxt[i])
{
y=tov[i];
for (int j=1,z;j<=key[y][0];++j)
if (rank[z=key[y][j]]>rank[x]) ans+=(cnt[z]++);
}
for (int i=last[x],y;i;i=nxt[i])
{
y=tov[i];
for (int j=1,z;j<=key[y][0];++j)
if (rank[z=key[y][j]]>rank[x]) --cnt[z];
}
}
}
int main()
{
freopen("palingenesis.in","r",stdin),freopen("palingenesis.out","w",stdout);
n=read(),m=read();
for (int i=1,x,y;i<=m;++i) x=read(),y=read(),insert(x,y),insert(y,x),++deg[x],++deg[y];
pre(),calc();
printf("%lld\n",ans);
fclose(stdin),fclose(stdout);
return 0;
}