2018.08.21 NOIP模拟 xorand(01trie)

版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/81909133

xorand

描述

有q次操作,每次操作是以下两种:
1、 加入一个数到集合中
2、 查询,查询当前数字与集合中的数字的最大异或值,最大and值,最大or值

输入

第一行1个正整数Q表示操作次数
接下来Q行,每行2个数字,第一个数字是操作序号OP(1,2),第二个数字是X表示操作的数字

输出

输出查询次数行,每行3个整数,空格隔开,分别表示最大异或值,最大and值,最大or值

样例输入

【输入样例1】

5
1 2
1 3
2 4
1 5
2 7

【输出样例1】

7 0 7
5 5 7

【样例解释1】

询问4时,已插入2、3,最大异或值为4^3=7,最大and值为4&3或4&2=0,最大or值为4|3=7
询问7时,已插入2、3、5,最大异或值为7^2=5,最大and值为7&5=5,最大or值为7|2=7|3=7|5=7

【输入样例2】

10
1 194570
1 202332
1 802413
2 234800
1 1011194
2 1021030
2 715144
2 720841
1 7684
2 85165

【输出样例2】

1026909 201744 1032061
879724 984162 1048062
655316 682376 1043962
649621 683464 1048571
926039 85160 1011199

样例输出

提示

对于%10的数据1<=Q<=5000
对于另%10的数据保证 X<1024
对于另%40的数据保证1<=Q<=100000
对于所有数据保证1<=Q<=1000000,1<=X<=2^20 保证第一个操作为1操作。

异或查询显然是01trie+贪心的常规套路,但问题就在于如何处理与和或的情况。
事实上,对于与操作,我们只考虑其为1的二进制位集合中有没有对应的数该位也为一。或操作类似,因此我们对于插入01trie的每一个数,将由其为1的二进制位下标组成的所有集合都给标记一遍,之后用类似于处理异或的方法从高到低位贪心缩小范围即可。
注意标记是可以记忆化的,所以时间复杂度有保证。

代码:

#include<bits/stdc++.h>
#define N 2000010
#define P 19
#define max(x,y) (x>y?x:y)
using namespace std;
inline int read(){
    int ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
inline void write(int x){
    if(x>9)write(x/10);
    putchar((x%10)^48);
}
int cnt=1,q,a[N],rt=1,son[N][2],flag[N],ans1,ans2,ans3;
inline void makeflag(int x){
    flag[x]=1;
    for(int i=0;i<=P;++i)if((x>>i&1)&&(!flag[x^(1<<i)]))makeflag(x^(1<<i));
}
inline void insert(int x){
    int p=rt;
    for(int i=P;~i;--i){
        int c=(x>>i)&1;
        if(!son[p][c])son[p][c]=++cnt;
        p=son[p][c];
    }
}
inline int query(int x){
    int p=rt,ret=0;
    for(int i=P;~i;--i){
        int c=((x>>i)&1^1);
        if(son[p][c]){
            p=son[p][c];
            if(c)ret|=1<<i;
        }
        else{
            p=son[p][c^1];
            if(c^1)ret|=1<<i;
        }
    }
    return ret^x;
}
inline int query1(int x){
    int p=rt,ret=0;
    for(int i=P;~i;--i){
        int c=(x>>i)&1;
        if(!c)continue;
        if(flag[ret|(1<<i)])ret|=(1<<i);
    }
    return ret&x;
}
inline int query2(int x){
    int p=rt,ret=0;
    for(int i=P;~i;--i){
        int c=(x>>i)&1;
        if(c)continue;
        if(flag[ret|(1<<i)])ret|=(1<<i);
    }
    return ret|x;
}
int main(){
    q=read();
    while(q--){
        int op=read(),x=read();
        if(op==1)makeflag(x),insert(x);
        else{
            write(query(x)),putchar(' ');
            write(query1(x)),putchar(' ');
            write(query2(x)),putchar('\n');
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/dreaming__ldx/article/details/81909133