CDOJ 1060 秋实大哥与快餐店 字典树

秋实大哥有一些菜,每个菜有标号CID,也会来一些客人,每个客人也有标号PID。

对于每个客人, PID^CID (此处为异或)值越大,他越喜欢。

输入:第一行是一个n(1<=n<=100000),表示现在有n道菜。接下来有一个m(1<=m<=100000),表示m个操作

接下来m行,有两种,一, 0 c:表示新研制出来一道标号为c的菜。二,1 p:表示来了一个标号为p的客人,请输出他最喜欢的菜。


字典树来做,用字典树按01分叉,从第20位开始分一直到第0位,然后将这个数保存进来,就是说,从根节点到叶子节点的路径就是这个叶子节点的值的二进制的第20位到第0位。

然后每来一个客人,就查询,查询时同样从最高位开始查,找与PID不同(因为是异或嘛)的支路往下查询,当然如果那个支路下是NULL,表示还没有这样的数,就走走与PID相同的路,然后按这个思想,一直走到第0位那里,对应的值就是他最喜欢的菜的标号。

为什么从最高位往最低位找不同的呢,因为某一位为1,它这一位所代表的值,比后面的所有位全为1代表的值加起来都大啊,找最大,就可以这样贪心地来找。

代码:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define bit_l 20
//2^17=131072
struct node
{
	int  pos;
	node *ch[2];
	node()
	{
		pos = 0;
		ch[0] = ch[1] = NULL;
	}
};
int n, m;
node *root;
void insert(int x)
{
	//printf("insert ");
	//printf("cid %d\n", CID[pos]);
	node *p = root;
	for (int i = 20; i >= 0; --i)
	{
		int f = (x & (1 << i)) != 0;
		//printf("%d ", f);
		if (p->ch[f] == NULL)
			p->ch[f] = new node();
		p = p->ch[f];
		if (i == 0)
			p->pos = x;
	}
	//printf("\n");
}
int query(int t)
{
	//printf("query  ");
	int pos = 0;
	node *p = root;
	for (int i = 20; i >= 0; --i)
	{
		int f = (t&(1 << i)) != 0;
		//printf("%d ", f);
		f = (f == 0) ? 1 : 0;
		if (p->ch[f] != NULL)
			p = p->ch[f];
		else
			p = p->ch[f == 1 ? 0 : 1];
		if (i == 0)
			pos = p->pos;
	}
	//printf("\n");
	return pos;
}
void destory(node *p)
{
	if (p != NULL)
	{
		destory(p->ch[0]);
		destory(p->ch[1]);
		delete p;
	}
}
int main()
{
	//freopen("input.txt", "r", stdin);
	scanf("%d", &n);
	root = new node();
	int f, t;
	for (int i = 1; i <= n; ++i)
	{
		scanf("%d", &t);
		insert(t);
	}
	scanf("%d", &m);
	while (m--)
	{
		scanf("%d%d", &f, &t);
		if (f == 0)
		{
			insert(t);
		}
		else if (f == 1)
			printf("%d\n", query(t));
	}
	destory(root);
	//system("pause");
	//while (1);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值