ZCMU - 1783: 秋实大哥与快餐店

题目链接:点击打开链接

题目大意:略。

解题思路:数组大小定义为:2e6+10,数组大小与 n,m 是无关的,只与 cid 的最大值相关,算出对应的最多位数,比如:此题目中 cid 最大值为 1000000,对应的二进制位数最多 20位,根据完全二叉树的结点公式,最多 2^21-1。因为这里是边作为 二进制位,结点作为 链接下一个结点的下标。又因为题目说了是 cid^pid 最大的数,所以根据异或相同则0,不同则1的性质可知,只要是高位二进制各异就是最大的数了,所以 query 函数先尽量找与自己不一样的二进制,实在找不到的话,再选择自己的二进制位

AC 代码

#include<bits/stdc++.h>
#include<cmath>

#define mem(a,b) memset(a,b,sizeof a);
#define INF 0x3f3f3f3f

using namespace std;

typedef long long ll;
const int maxn=1e5+10;

int n,m,cnt;
int trie[21*maxn][2];
int val[21*maxn];

void init()
{
    cnt=0;
    mem(val,0); mem(trie,0);
}

void add(int cid)
{
    int rt=0,id;
    for(int i=19;i>=0;i--) // 从 19 开始是因为从最高位开始操作
    {
        id=(cid>>i)&1;
        if(!trie[rt][id]) trie[rt][id]=++cnt; // trie[rt][id] 不能等于 0,以免与初始化混淆
        rt=trie[rt][id];
    }
    val[rt]=cid;
}

int query(int pid)
{
    int rt=0,id;
    for(int i=19;i>=0;i--) // 同上
    {
        id=(pid>>i)&1;
        if(trie[rt][id^1]) rt=trie[rt][id^1];
        else rt=trie[rt][id];
    }
    return val[rt];
}

int main()
{
    while(~scanf("%d",&n))
    {
        init();
        int cid;
        for(int i=0;i<n;i++)
        {
            scanf("%d",&cid);
            add(cid);
        }

        scanf("%d",&m);
        int op,id;
        for(int i=0;i<m;i++)
        {
            scanf("%d%d",&op,&id);
            if(op) printf("%d\n",query(id));
            else add(id);
        }
    }

    return 0;
}

猜你喜欢

转载自blog.csdn.net/dream_weave/article/details/81203759