维护一个集合,支持如下几种操作:
I x
,插入一个整数 x;Q x
,询问整数 x 是否在集合中出现过;
现在要进行 N次操作,对于每个询问操作输出对应的结果。
输入格式
第一行包含整数 N,表示操作数量。
接下来 N 行,每行包含一个操作指令,操作指令为 I x
,Q x
中的一种。
输出格式
对于每个询问指令 Q x
,输出一个询问结果,如果 x在集合中出现过,则输出 Yes
,否则输出 No
。
每个结果占一行。
数据范围
1≤N≤10^5
−10^9≤x≤10^9
//拉链法
#include<bits/stdc++.h>
using namespace std;
const int N = 100003;//对N求余,一般用质数
//映射后的值如果相同,就放入一个单链表
//h[k],k为映射后的值,h[k]存储单链表表头的下标
//h[N]每一个元素就相当于是每一个链表的头节点
//e[N],ne[N],idx就是单链表存储
int h[N],e[N],ne[N],idx;
void insert(int x)
{
//x可能为负数
int k = abs(x) % N;
//头插法
e[idx] = x;//e[]存储原来的值
ne[idx] = h[k];//ne[]指向原来链表的表头
h[k] = idx ++;//h[k]存储链表表头的下标
}
bool query(int x)
{
int k = abs(x) % N;
//i就是链表中的下一个元素的下标
for(int i = h[k]; i != -1; i = ne[i])
{
if(e[i] == x) return true;
}
return false;
}
int main()
{
int n;cin >> n;
string op;int x;
memset(h,-1,sizeof h);//开始时h[]都指向-1,即没有链表
while(n --)
{
cin >> op >> x;
if(op[0] == 'I')
{
insert(x);
}
else
{
if(query(x)) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}
//开放寻址法
#include<bits/stdc++.h>
using namespace std;
const int N = 200003;//开放寻址法一般开两倍,对N求余,一般用质数
const int null = 0x3f3f3f3f;//若h[]中存储该数没说明该位置没被占用
int h[N];//h[k]k为映射后的值,h[k]存储原来的值
int find(int x)
{
int k = abs(x) % N;
while(h[k] != null && h[k] != x)//该位置被占用,且该位置上存储的数不是x,就往后找
{
k ++;
if(k == N) k = 0;//后边的位置都被占用就从0开始找
}
return k;
}
int main()
{
int n;cin >> n;
string op;int x;
memset(h,0x3f,sizeof h);//开始时h[]都指向-1,即没有链表
while(n --)
{
cin >> op >> x;
int k = find(x);//找到映射后的下标
if(op == "I") h[k] = x;
else
{
if(h[k] != null) cout << "Yes" << endl;
else cout << "No" << endl;
}
}
return 0;
}