zoukankan      html  css  js  c++  java
  • 【BZOJ2741】L-分块+可持久化trie

    测试地址:L
    做法:本题需要用到分块+可持久化trie。
    我们知道,一个连续异或和实际上就等于两个前缀异或和的异或,因此我们求出前缀异或和,转换成一个新的问题:求区间内两个数异或的最大值。这个东西直接用数据结构做不好做,而且又强制在线不能用莫队,因此考虑相似的分块。
    首先对序列分块,然后对于每一块,令mx(i,j)表示第i+1块左端点到点j区间中最大的两个数的异或值,显然这个可以用一个trie很快地做出来,时间复杂度为O(31nn)。接着对于每一个询问,如果这个询问的左右端点在同一块内,直接用trie暴力算出结果即可,时间复杂度为O(31n)。否则,这个区间就会被左端点所在块的右边界分割成两段,其中右边那段可以直接用前面算出的mx进行O(1)计算,而左边那段可以直接暴力O(31n)进行计算,关键是如何求出一个数在左边,一个数在右边的最大异或值呢?只需要对整个序列建一个可持久化trie,然后对于左边的每一个点,在可持久化trie对应的区间中贪心即可,时间复杂度为O(31n)
    于是我们就以O(31nn)的时间复杂度完成了这一题。
    以下是本人代码:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n,m,blocksiz,a[12010],pre[12010],suf[12010],block[12010],totp,tot;
    int rt[12010]={0},nowrt[12010]={0},mx[120][12010]={0};
    int sum[400010]={0},ch[400010][2]={0};
    
    void insert(int v,int last,int x,bool mode)
    {
        sum[v]=sum[last]+1;
        for(int i=30;i>=0;i--)
        {
            bool f=(x&(1<<i));
            if (mode) ch[v][f]=++totp;
            else ch[v][f]=++tot;
            ch[v][!f]=ch[last][!f];
            v=ch[v][f];
            last=ch[last][f];
            sum[v]=sum[last]+1;
        }
    }
    
    int query(int v,int last,int x)
    {
        int ans=0;
        for(int i=30;i>=0;i--)
        {
            ans<<=1;
            bool f=(x&(1<<i));
            f=!f;
            if (sum[ch[v][f]]-sum[ch[last][f]]>0) ans++;
            else f=!f;
            v=ch[v][f];
            last=ch[last][f];
        }
        return ans;
    }
    
    void init()
    {
        totp=5000;
        for(int i=0;(i+1)*blocksiz<=n;i++)
        {
            tot=0;
            ch[1][0]=ch[1][1]=0;
            nowrt[(i+1)*blocksiz-1]=0;
            for(int j=(i+1)*blocksiz;j<=n;j++)
            {
                nowrt[j]=++tot;
                insert(nowrt[j],nowrt[j-1],suf[j],0);
                mx[i][j]=max(mx[i][j-1],query(nowrt[j],0,suf[j+1]));
            }
        }
        for(int i=1;i<=n;i++)
        {
            rt[i]=++totp;
            insert(rt[i],rt[i-1],pre[i],1);
        }
    }
    
    int solve(int L,int R)
    {
        int ans=0;
        if (block[L]==block[R])
        {
            tot=0;
            nowrt[L-1]=0;
            for(int i=L;i<=R;i++)
            {
                nowrt[i]=++tot;
                insert(nowrt[i],nowrt[i-1],suf[i],0);
                ans=max(ans,query(nowrt[i],0,suf[i+1]));
            }
        }
        else
        {
            ans=mx[block[L]][R];
            for(int i=L;i<(block[L]+1)*blocksiz;i++)
                ans=max(ans,query(rt[R],rt[(block[L]+1)*blocksiz-1],pre[i-1]));
            tot=0;
            nowrt[L-1]=0;
            for(int i=L;i<(block[L]+1)*blocksiz;i++)
            {
                nowrt[i]=++tot;
                insert(nowrt[i],nowrt[i-1],suf[i],0);
                ans=max(ans,query(nowrt[i],0,suf[i+1]));
            }
        }
        return ans;
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        blocksiz=(int)sqrt(n)+1;
        pre[0]=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            block[i]=i/blocksiz;
            pre[i]=pre[i-1]^a[i];
        }
        suf[n+1]=0;
        for(int i=n;i>=1;i--)
            suf[i]=suf[i+1]^a[i];
        init();
    
        int lastans=0;
        for(int i=1;i<=m;i++)
        {
            int x,y,l,r;
            scanf("%d%d",&x,&y);
            x=((ll)x+(ll)lastans)%(ll)n+1;
            y=((ll)y+(ll)lastans)%(ll)n+1;
            l=min(x,y),r=max(x,y);
            printf("%d
    ",lastans=solve(l,r));
        }
    
        return 0;
    }
  • 相关阅读:
    什么是 bean 的自动装配?
    什么是 Spring 的内部 bean?
    什么是 Spring 的 MVC 框架?
    Spring AOP and AspectJ AOP 有什么区别?
    解释 JDBC 抽象和 DAO 模块?
    volatile 类型变量提供什么保证?
    一个 Spring Bean 定义 包含什么?
    什么是 Spring MVC 框架的控制器?
    使用 Spring 访问 Hibernate 的方法有哪些?
    什么是 Callable 和 Future?
  • 原文地址:https://www.cnblogs.com/Maxwei-wzj/p/9793262.html
Copyright © 2011-2022 走看看