hdu6184php
題意是讓咱們找出全部的這樣的圖形:node
咱們只須要求出每條邊分別在多少個三元環中,記爲\(x\),再而後以該點爲中心的圖形數就是\({x \choose 2}\)ios
因此咱們只需找出全部三元環ide
聽說這是一個套路題ui
咱們將全部無向邊改成有向邊,由度數小的向度數大的連邊,度數相同就由編號小的向編號大的
容易發現這樣建圖必定是一個\(DAG\)
而後咱們枚舉邊,將邊的兩端點出邊的到達的點打上標記,當一個點被打上同一個標記時,就成環了
由於是\(DAG\)容易發現這樣找環不會重複spa
而後就是時間複雜度證實
是\(O(m\sqrt{m})\)的
咱們只需證實每一個點出度不大於\(\sqrt{m}\)
假設有一個點出度大於\(\sqrt{m}\),那麼由建邊方式咱們至知道出邊到達的點度數不比該點小,這樣總的邊數就大於\(m\)了,不符
因此點的度數是\(O(\sqrt{m})\)的code
爲何在\(hdu\)使用\(pair\)會\(CE\) = =blog
#include<algorithm> #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<utility> #define Redge(u) for (int k = h[u]; k; k = ed[k].nxt) #define REP(i,n) for (int i = 1; i <= (n); i++) #define mp(a,b) (node){a,b} #define cls(s) memset(s,0,sizeof(s)) #define cp node #define LL long long int using namespace std; const int maxn = 100005,maxm = 200005,INF = 1000000000; inline int read(){ int out = 0,flag = 1; char c = getchar(); while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();} while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();} return out * flag; } struct node{ int first,second; }; int h[maxn],ne; struct EDGE{int to,nxt,id;}ed[maxm]; inline void build(int u,int v,int x){ ed[++ne] = (EDGE){v,h[u],x}; h[u] = ne; } int de[maxn],a[maxm],b[maxm],now,n,m,ans[maxm]; cp vis[maxn]; int main(){ while (~scanf("%d%d",&n,&m)){ ne = now = 0; REP(i,n) vis[i] = mp(0,0),h[i] = de[i] = 0; REP(i,m){ ans[i] = 0; a[i] = read(); b[i] = read(); de[a[i]]++; de[b[i]]++; } REP(i,m){ if (de[a[i]] > de[b[i]] || (de[a[i]] == de[b[i]] && a[i] > b[i])) swap(a[i],b[i]); build(a[i],b[i],i); } REP(i,m){ now++; Redge(a[i]) vis[ed[k].to] = mp(now,ed[k].id); Redge(b[i]) if (vis[ed[k].to].first == now){ ans[i]++; ans[ed[k].id]++; ans[vis[ed[k].to].second]++; } } LL ret = 0; REP(i,m) if (ans[i] > 1) ret += ans[i] * (ans[i] - 1) / 2; printf("%lld\n",ret); } return 0; }