您的位置:首页 > 其它

BZOJ 3689 异或之

2016-10-22 10:11 232 查看
TRIE树+堆

如果只求最小的,我们可以建出TRIE树,对每一个数都跑一边求第二小(最小的是自己异或自己),这样一定包含了所有数的异或最小值,然后找最小的即可。

如果还需要求第二小,在排除第一小的情况下,我们把组成第一小的那个数在TRIE树上求一个第三小,这样同样依然包含了所有数的当前异或最小值,以此类推,堆维护即可。

注意a^b = b^a,也就是说一个值会出现两次,所以k应取k*2

#include<cstdio>
#include<queue>
#include<map>
#define N 100005
#define H 30
using namespace std;
int a
, use
;

map<pair<int,int>,bool> vis;

int nodecnt;
struct node
{
node *ch[2];
int siz;
node(){ch[0]=ch[1]=NULL;siz=0;}
}s[N*50];

struct TRIE
{
node *root;
void init()
{
root = &s[++nodecnt];
}
void insert(int x)
{
node *p = root;
for(int i = H, pos = 1<<H; ~i; i--, pos>>=1)
{
if(!p->ch[0])p->ch[0]=&s[++nodecnt];
if(!p->ch[1])p->ch[1]=&s[++nodecnt];
int son = x&pos?1:0;
p=p->ch[son];
p->siz++;
}
}
int find(int x, int k)//第k小
{
node *p = root;
int ret = 0;
for(int i = H, pos = 1<<H; ~i; i--, pos>>=1)
{
int son = x&pos?1:0;
if(p->ch[son]->siz >= k)
{
ret<<=1;
p=p->ch[son];
}
else
{
ret<<=1;
ret|=1;
k-=p->ch[son]->siz;
p=p->ch[son^1];
}
}
return ret;
}
}trie;

struct number
{
int x, v;
number(int a, int b):x(a),v(b){}
friend bool operator < (number a, number b)
{
return a.v>b.v;
}
};

int main()
{
int n, k;
scanf("%d%d",&n,&k);
trie.init();
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
trie.insert(a[i]);
use[i]=1;
}

priority_queue<number> q;

for(int i = 1; i <= n; i++)
{
++use[i];
int num = trie.find(a[i],use[i]);
q.push(number(i,num));
}

for(int i = 1, ii = 2*k; i < ii; i++)
{
number x = q.top(); q.pop();
if(i&1)printf("%d ",x.v);
int pos = x.x, num;

if(use[pos]==n)continue;
use[pos]++;
num = trie.find(a[pos],use[pos]);
q.push(number(pos,num));
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: