zoukankan      html  css  js  c++  java
  • bzoj 3261: 最大异或和

    表示bzoj把本校大佬Cherish_OI当成僵尸用户(ORZ

    现在都还在封我们学校IP(管理员怕是看不到我的blog。。。

    OK那么这题又get一个新姿势,可持久化字典树。听说这东西解决异或和是常规操作?

    这个东西呢,我第一感觉就是跟主席树很像,然后吐槽一波空间消耗极大

    对于每个前缀异或和建树,然后前缀和,这里的前缀和是每个位0,1的数量(就是主席树嘛)

    然后query的时候,因为答案是sum[p-1]^sum[n]^x,而sum[n]^x已知,那么就去字典树里l-1~r的区间由大到小去找和sum[n]^x的当前二进制位不同数是否存在,也就是if(当前区间c>0),就是记录答案。

    细节:一开始要插一个0的数,因为当p取1,也就是如果我们把全部的数异或起来是最大的,那答案就是sum[n]^x,在前面多增加一位方便。并且如果不这么做,找的时候就要从l-2~r-1里面找,因为前缀和的缘故sum的总数是要比值的数量少1的。

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    using namespace std;
    
    int Bin[30];
    struct Trie
    {
        int w[2],sum;
    }tr[21000000];int trlen,rt[610000];
    int maketree(int x,int d)
    {
        int y=++trlen;int ret=y;
        for(int i=23;i>=0;i--)
        {
            tr[y].w[0]=tr[x].w[0];
            tr[y].w[1]=tr[x].w[1];
            tr[y].sum=tr[x].sum+1;
            
            int t;
            if((d&Bin[i])==0)t=0;
            else t=1;
            
            x=tr[x].w[t];
            tr[y].w[t]=++trlen;
            y=tr[y].w[t];
        }
        tr[y].sum=tr[x].sum+1;
        return ret;
    }
    int query(int x,int y,int d)
    {
        int ans=0;
        for(int i=23;i>=0;i--)
        {
            int t;
            if((d&Bin[i])==0)t=0;
            else t=1;
            
            if(tr[tr[y].w[t^1]].sum-tr[tr[x].w[t^1]].sum>0)
            {
                ans+=Bin[i];
                x=tr[x].w[t^1], y=tr[y].w[t^1];
            }
            else
                x=tr[x].w[t], y=tr[y].w[t];
        }
        return ans;
    }
    
    int a[610000],s[610000];
    char ss[10];
    int main()
    {
        Bin[0]=1;for(int i=1;i<=30;i++)Bin[i]=Bin[i-1]*2;
        int n,m;
        scanf("%d%d",&n,&m);n++;
        s[1]=0;
        for(int i=2;i<=n;i++)
            scanf("%d",&a[i]), s[i]=s[i-1]^a[i];
        trlen=0;
        for(int i=1;i<=n;i++)
            rt[i]=maketree(rt[i-1],s[i]);
        
        int l,r,p;
        while(m--)
        {
            scanf("%s",ss+1);
            if(ss[1]=='A')
            {
                n++;
                scanf("%d",&a[n]), s[n]=s[n-1]^a[n];
                rt[n]=maketree(rt[n-1],s[n]);
            }
            else
            {
                scanf("%d%d%d",&l,&r,&p);
                printf("%d
    ",query(rt[l-1],rt[r],s[n]^p));
            }
        }
        return 0;
    }
  • 相关阅读:
    DbHelper数据操作类
    获取cpu序列号,硬盘ID,网卡MAC地址
    用户必备资料 103个Windows XP运行命令
    在Web.config配置文件中自定义配置节点
    Microsoft.NET PetShop4架构与技术分析
    数字转英文(货币)大写(vb)
    如何计算dba_tables中的avg_row_len.
    行选移与行链接的介绍
    如何使用动态SQL
    如何导致全表扫描原因
  • 原文地址:https://www.cnblogs.com/AKCqhzdy/p/8648525.html
Copyright © 2011-2022 走看看