標題這倆東西看起來似乎八杆子打不着,不過只是我在學三元環的時候纔剛學到哈希表是個什麼東西。。。
關於三元環的解法感覺Claris寫的就很不錯→%%Claris
我在這裏再簡單的說一下複雜度的相關;
首先可以改成單向邊,全都改成由大的點指向小的點(我自己寫的是相反的。。。)然後枚舉每一個點i,再枚舉這個點的出邊,如果連出的這個點(設爲k)出度小於sqrt(m)的話,再暴力枚舉一下另一個點,只看這一部分複雜度是n根號m的;
如果連出的點k的出度大於sqrt(m),那麼就暴力找所有i的其他出點,看是否能組成三元環,由於出度大於sqrt(m)的最多隻有sqrt(m)個點,所以這一部分是m根號m的;
至於第二種情況找第三個點的時候爲什麼要從一開始的i開始找,如果i出度大於根m,那i和k可能的組合是很少的,而如果i出度小於根號m,那i向外找的點是小於根號m的,總體平均下來還是m根號m
不得不說一下Claris神奇的寫法,他給每條邊先排了個序,再按順序插入鄰接表中,這樣保證每個點向外依次遍歷到的點是單調的,可以省掉一部分常數;
至於哈希表,之前一直以爲哈希表只是簡單的哈希,把值模一下放數組裏就完了,以至於我無數次臉黑撞哈希;
今天我纔剛發現,原來真正的哈希表是不會有哈希衝突的,其原理是將哈希值相同的數據存一個鄰接鏈表,每次都在這個鄰接鏈表裏遍歷一遍看是否有要查找的元素;
這樣一來正確性是可以保證的,而且由於撞哈希的概率不會太高,複雜度均攤下來也是O(1)的;
放一波代碼orz(感覺表達能力好弱。。。寫的這些個鬼東西將來自己都不一定能再看懂)
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
const int maxn=100005;
using std::max;
const int maxm=250005;
int sq,v[maxn],du[maxn],n,m;
struct asd{
int next,x,y;
}edge[maxm*4];
const int mod=(1<<23)-1;
int hnode[mod+1],node[maxn];
int etot=0;
void add(int x,int y){
edge[++etot].next=node[x];
edge[etot].y=y;
node[x]=etot;
}
int hash(int x,int y){
return (x<<8|y)&mod;
}
void insert(int x,int y){
int val=hash(x,y);
edge[++etot].next=hnode[val];
edge[etot].x=x,edge[etot].y=y;
hnode[val]=etot;
}
bool vis(int x,int y){
int val=hash(x,y);
for(int i=hnode[val];i;i=edge[i].next)if(edge[i].x==x&&edge[i].y==y)return true;
return false;
}
void read(int &x){
x=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
sq=sqrt((double)m)+0.5;
for(int i=1;i<=n;i++)read(v[i]);
while(m--){
int tp1,tp2;
read(tp1),read(tp2);
if(tp1>tp2)std::swap(tp1,tp2);
add(tp1,tp2);
du[tp1]++;
insert(tp1,tp2);
}
LL ans=0;
for(int i=1;i<=n;i++){
for(int j=node[i];j;j=edge[j].next){
int vi=v[edge[j].y]> v[i] ? v[edge[j].y] : v[i];
if(du[edge[j].y]<sq){
for(int k=node[edge[j].y];k;k=edge[k].next)
if(vis(i,edge[k].y))ans+=(LL)v[edge[k].y]>vi ? v[edge[k].y] : vi;
}
else {
for(int k=node[i];k;k=edge[k].next){
if(edge[k].y>edge[j].y&&vis(edge[j].y,edge[k].y))ans+=(LL)v[edge[k].y]>vi ? v[edge[k].y] : vi;
}
}
}
}
printf("%lld\n",ans);
return 0;
}
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define LL long long
const int maxn=100005;
using std::max;
const int maxm=250005;
int sq,du[maxn],n,m;
struct asd{
int next,x,y,c;LL vi;
}edge[maxm*4];
const int mod=999983;
const int p=1000000007;
int hnode[mod],node[maxn];
int etot=0;
int add(int x,int y,LL v,int zt){
edge[++etot].next=node[x];
edge[etot].y=y;
edge[etot].c=zt;
edge[etot].vi=v;
node[x]=etot;
return etot;
}
int hash(int x,int y,int z){
return(int)(((LL)x*(LL)n*8ll+(LL)y*8ll+z)%(LL)mod);
}
void insert(int x,int y,LL v,int zt){
int val=hash(x,y,zt);
edge[++etot].next=hnode[val];
edge[etot].x=x,edge[etot].y=y;
edge[etot].c=zt;
edge[etot].vi=v;
hnode[val]=etot;
}
int tot3=0;
int vis(int x,int y,int zt){
int val=hash(x,y,zt);
for(int i=hnode[val];i;i=edge[i].next){
tot3++;
if(edge[i].x==x&&edge[i].y==y&&edge[i].c==zt)return i;
}
return 0;
}
void read(int &x){
x=0;
char c=getchar();
while(c<'0'||c>'9')c=getchar();
while(c>='0'&&c<='9'){
x=x*10+c-'0';
c=getchar();
}
}
int main()
{
// freopen("force.in","r",stdin);
// freopen("force.out","w",stdout);
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&m);
sq=sqrt((double)m)+0.5;
while(m--){
int tp1,tp2,tp3;
read(tp1),read(tp2),read(tp3);
char c[3];
scanf("%s",c);
int zt=0;
if(c[0]=='R')zt=1;
else if(c[0]=='G')zt=1<<1;
else zt=1<<2;
if(tp1>tp2)std::swap(tp1,tp2);
int tv=vis(tp1,tp2,zt);
if(!tv){
add(tp1,tp2,(LL)tp3,zt);
insert(tp1,tp2,(LL)tp3,zt);
du[tp1]++;
}
else {
(edge[tv].vi+=(LL)tp3)%=p,(edge[tv-1].vi+=(LL)tp3)%=p;
}
}
int ans=0;
for(int i=1;i<=n;i++){
for(int j=node[i];j;j=edge[j].next){
int zt=edge[j].c;
if(du[edge[j].y]<=sq){
for(int k=node[edge[j].y];k;k=edge[k].next)
if(zt^edge[k].c)
{
int nzt=7^zt^edge[k].c;
int tv=vis(i,edge[k].y,nzt);
if(tv)(ans+=(LL)(edge[tv].vi*edge[k].vi%p)*edge[j].vi%p)%=p;
}
}
else {
for(int k=node[i];k;k=edge[k].next)
if(zt^edge[k].c)
{
int nzt=7^zt^edge[k].c;
int tv=vis(edge[j].y,edge[k].y,nzt);
if(edge[k].y>edge[j].y&&tv)(ans+=(LL)(edge[tv].vi*edge[k].vi%p)*edge[j].vi%p)%=p;
}
}
}
}
printf("%d\n",ans);
return 0;