哈希表

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<random>
#include<time.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<unordered_map>
#define ll long long
using namespace std;
using namespace __gnu_pbds;
const int MAXN=1e5+10;
int pos[MAXN],cnt;mt19937 R;
struct node{int x,y,w;};vector <node> e;
inline bool cmp(node x,node y)
	{return x.w<y.w;}
"ValueType" <ll,int> H;
inline ll F(int x,int y)
	{return ((1ll*x)<<32)|y;}
signed main()
{
	int n=100000,m=100000,q=250;
	for(int i=1;i<=n;++i) pos[i]=i;
	for(int i=1,x,y,w;i<=m;++i)//插入 m 个数
	{
		w=R()%123456789+1;
		x=R()%n+1,y=R()%n+1;
		if(x>y) swap(x,y);ll pos=F(x,y);
		if(!H[pos]) H[pos]=w;
		else H[pos]=min(H[pos],w);
	}
	cerr<<clock()*1.0/CLOCKS_PER_SEC<<'\n';
	for(auto now:H)//遍历一遍
	{
		ll pos=now.first;int w=now.second;
		int x=pos>>32,y=pos^((1ll*x)<<32);
		e.push_back({x,y,w});
	}
	cerr<<clock()*1.0/CLOCKS_PER_SEC<<'\n';
// 	sort(e.begin(),e.end(),cmp);
	for(int i=0;i<e.size();++i)//修改为编号
		H[F(e[i].x,e[i].y)]=i;
	cerr<<clock()*1.0/CLOCKS_PER_SEC<<'\n';
	for(int o=1,k=400;o<=q;++o)//查询一些东西
	{
		shuffle(pos+1,pos+1+n,R);
		for(int i=0;i<k;++i) for(int j=i+1;j<k;++j)
		{
			int x=pos[i],y=pos[j];
			if(x>y) swap(x,y);ll POS=F(x,y);
			if(H.find(POS)!=H.end()) ++cnt;
		}
	}
	cerr<<clock()*1.0/CLOCKS_PER_SEC<<'\n';return 0;
}

你写出了这样的代码,大概是想找出 \(q=250\) 个点集大小为 \(k=400\) 的导出子图。

其中你需要实现一个 pairint 的映射,于是你将 pair 压成了 long long

尽管不一定很卡常,但是你精益求精的使 "ValueType" = gp_hash_table,打开了 O2

然后你发现输出是:

0.727675
0.729566
1.07756

甚至查询都跑不出来。

你不以为意,大概只是正好这样的数据能卡掉 gp_hash_table,但是没关系,因为你还有 cc_hash_table 可以替换。

你兴高采烈的将 cc_hash_table 替换上,你发现输出是:

0.008778
0.01072
0.011504
0.350058

不错,很快,你提交后吃了一发罚时,它说你 TLE 了。

你更加疑惑了,但是你认为可能常数藏在一些看不见的地方,于是开始卡常。

但是当然你想到用 unordered_map 来试一试,你发现输出是:

0.010581
0.012657
0.013935
0.600974

明显比 cc_hash_table 慢啊,于是你继续卡常。

但是两个多小时后你卡不动了,你突然想到了什么,对 cc_hash_table 打开了 ubsan:

0.023092
0.02854
0.031228
/usr/include/c++/9/ext/pb_ds/detail/cc_hash_table_map_/cc_ht_map_.hpp:530:15: runtime error: member access within null pointer of type 'struct entry'
0.915729

所以或许是 cc_hash_table 有 bug?我不知道啊。

但是对于 gp_hash_table

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
#include<unordered_map>
#define ll long long
using namespace std;
using namespace __gnu_pbds;
gp_hash_table <ll,int> H;
signed main()
{
	int n=500000,cnt=0;
	for(int i=1,x,y;i<=n;++i)
	{
		x=rand()%n+1,y=rand()%n+1;
		// if(x>y) swap(x,y);
		H[(1ll*x)<<32|y]=i;
	}
}

这个跑 \(0.15s\),而把注释删了跑 \(9.9s\)。大概是因为过于不均匀?

链接

所以好像应该 gp_hash_table<int,gp_hash_table<int,int>> 这样写。

posted @ 2024-10-31 18:01  int_R  阅读(82)  评论(7编辑  收藏  举报