• cf842D 01字典树|线段树 模板见hdu4825


    一般异或问题都可以转换成字典树的问题,,我一开始的想法有点小问题,改一下就好了

    下面的代码是逆向建树的,数据量大就不行

    /*3
    01字典树
    根据异或性质,a1!=a2 ==> a1^x1^..^xn != a2^x1^..an 
    把修改转换成不同的询问
    先把初始集合里没有的数建立成字典树
    每次询问找的是字典树里异或x最小的值 
    */
    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 300005
    int buf[maxn];
    void getbuf(int a){
        for(int i=1;i<=20;i++)
            buf[i]=a%2,a/=2;
        for(int i=1,j=20; i<=j; i++,j--)         
            swap(buf[i],buf[j]);
    }
    
    struct Trie{
        int root,L;
        int nxt[maxn*30][2],end[maxn*30];
        int newnode(){
            nxt[L][0]=nxt[L][1]=-1;
            return L++;
        }
        void init(){
            L=0;root=newnode();
        }
        void insert(int a){
            getbuf(a);
    //for(int i=1;i<=20;i++)printf("%d ",buf[i]);
            int now=root;
            for(int i=1;i<=20;i++){
                if(nxt[now][buf[i]]==-1)
                    nxt[now][buf[i]]=newnode();
                now=nxt[now][buf[i]]; 
            }
            end[now]=a;
        }
        int query(int a){//要找和a异或最小的数,就是碰到1时就往1走,碰到0时就往0走 
            getbuf(a);
    //for(int i=1;i<=20;i++)printf("%d ",buf[i]);
            int now=root;
            for(int i=1;i<=20;i++){
                if(nxt[now][buf[i]]==-1)
                    now=nxt[now][buf[i]^1];
                else now=nxt[now][buf[i]];
            }
            return end[now];
        }
    }tr;
    int n,m,flag[maxn],a,Max,x;
    vector<int>v;
    int main(){
        tr.init();
        cin>>n>>m;
        for(int i=1;i<=n;i++){
            cin>>a;flag[a]=1,Max=max(a,Max);
        }
        for(int i=0;i<=300000;i++)
            if(flag[i]==0)v.push_back(i);
        for(int i=0;i<v.size();i++)
            tr.insert(v[i]);
    
        m--,cin>>x;
        printf("%d
    ",tr.query(x)^x);
        while(m--){
            cin>>a;
            x^=a;
            printf("%d
    ",tr.query(x)^x);
        }
    }

    如果是把集合中存在的元素进行建树,就不会出现字典树大小无法确定的问题,但是每次查询要改一下,即如果第i位是1,那就往字典树的0子树找,反之往1子树找,并且如果先找的子树已经满了,即mex的结果不可能再这棵子树中找到,那么就往另一颗子树找即可

    #include <stdio.h>
    #include <string.h>
    #include<iostream>
    #define MAX(a,b) ((a)>(b)?(a):(b))
    #define NODE 3200010
    #define N 300010
    using namespace std;
    int n;
    int v[N];
    int node;
    int next[NODE][2];
    int end[NODE];
    int num[NODE][2];
    bool vis[NODE];
    void add(int cur,int k)
    {
        memset(next[node],0,sizeof(next[node]));
        end[node]=0;
        next[cur][k]=node++;
    }
    int cal(int x)
    {
        int i,k,cur=0,t1;
        int res=0;
        for(i=19;i>=0;i--)
        {
            k=((1<<i)&x)?1:0;
            if(num[cur][k]>=1<<(i)){
                res+=1<<i;
                cur=next[cur][1-k];
            }else{
                cur=next[cur][k];
            }
            if(cur==0)break; //这里是为了当进入到一个个数为0的分支,可以直接break
        }
        //return (x^end[cur]); 如果是求最大值
        return res;
    }
    int main()
    {
        int i,j,k,x,cur;
        int ans,m;
        //freopen("in.txt","r",stdin);
        while(~scanf("%d %d",&n,&m))
        {
            node=1;
            memset(next[0],0,sizeof(next[0]));
            for(i=0;i<n;i++)
            {
                scanf("%d",&x);
                if(vis[x])continue;
                vis[x]=1;
                v[i]=x;
                cur=0;
                for(j=19;j>=0;j--)
                {
                    k=((1<<j)&x)?1:0;
                    if(next[cur][k]==0)add(cur,k);
                    num[cur][k]++;
                    cur=next[cur][k];
                }
                end[cur]=x;
            }
            int t1,t2;
            t1=0;
            for(ans=i=0;i<m;i++){ //求最大值是max(ans,cal(v[i]))
                cin >> t2;
                t1^=t2;
                cout << cal(t1) << endl;
            }
        }
        return 0;
    }

    另外这题用线段树解也可以,即建600000个结点,每个叶子结点维护的就是元素中的集合,然后每次查询还是按01字典树找最小异或值那一套方法就行了

  • 相关阅读:
    Socket实现Web应用的本质
    板凳要坐十年冷 代码不写一句空
    Python写的刷QB钓鱼盗号软件
    除法细节_Python小知识点00005
    标识符,变量的命名_Python小知识00003
    类和ID选择器的区别
    十分钟搞定CSS选择器
    HTML引入CSS样式三种方法及优先级
    CSS代码语法
    html form <label>标签基础语法结构与使用案例教程
  • 原文地址:https://www.cnblogs.com/zsben991126/p/10355237.html
Copyright © 2020-2023  润新知