BZOJ 3498: PA2009 Cakes【三元环】
3498: PA2009 Cakes
【题目描述】
传送门
【题解】
求解三元环,枚举每条边,然后枚举点,判断是否组成三元环(可以用hash来判断),复杂度。
代码如下
#include<cmath>
#include<cstdio>
#include<vector>
#include<cctype>
#include<algorithm>
using namespace std;
const int MOD=(1<<23)-1;
int n,m,Size,W[100005],C[100005];
long long Ans;
struct xcw{
int x,y;
bool operator <(const xcw b)const{return x<b.x||x==b.x&&y<b.y;}
}a[250005];
struct Edge{
int tot,lnk[100005],son[250005<<1],nxt[250005<<1],F[250005<<1],hlnk[MOD+5];
void Add(int x,int y){son[++tot]=y;nxt[tot]=lnk[x];lnk[x]=tot;}
int hsh(int x,int y){return (x<<8|y)&MOD;}
void Add_hsh(int x,int y){
int j=hsh(x,y);
son[++tot]=y;F[tot]=x;
nxt[tot]=hlnk[j];hlnk[j]=tot;
}
bool Fnd(int x,int y){
int i=hsh(x,y);
for(int j=hlnk[i];j;j=nxt[j]) if(x==F[j]&&y==son[j]) return 1;
return 0;
}
}E;
vector <int> Son[100005];
int read(){
int ret=0;char ch=getchar();bool f=1;
for(;!isdigit(ch);ch=getchar()) f^=!(ch^'-');
for(; isdigit(ch);ch=getchar()) ret=(ret<<3)+(ret<<1)+ch-48;
return f?ret:-ret;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("3498.in","r",stdin);
freopen("3498.out","w",stdout);
#endif
n=read(),m=read();Size=sqrt(m);
for(int i=1;i<=n;i++) W[i]=read();
for(int i=1;i<=m;i++){
a[i]=(xcw){read(),read()};
if(a[i].x<a[i].y) swap(a[i].x,a[i].y);
C[a[i].x]++;
}
sort(a+1,a+1+m);
for(int i=1;i<=m;i++) E.Add_hsh(a[i].x,a[i].y),E.Add(a[i].x,a[i].y),Son[a[i].x].push_back(a[i].y);
for(int i=3;i<=n;i++)
for(int j=E.lnk[i];j;j=E.nxt[j]){
int x=E.son[j];
if(C[x]>Size){
for(int k=E.nxt[j];k;k=E.nxt[k]){
int y=E.son[k];
if(y>=x) continue;
if(E.Fnd(x,y)) Ans+=max(W[i],max(W[x],W[y]));
}
}else{
for(int k=E.lnk[x];k;k=E.nxt[k]){
int y=E.son[k];
if(E.Fnd(i,y)) Ans+=max(W[i],max(W[x],W[y]));
}
}
}
printf("%lld\n",Ans);
return 0;
}