【BZOJ2741】【FOTILE模拟赛】L 可持久化字典树+分块

广告:

#include 
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44496739");
}

题解:

首先我们处理出来 sum[0,n] 作为异或前缀和,然后答案就不再是 [l,r] 中间某段区间的异或和,而转化成求了 [l1,r] 中任意两点异或和的最大值。

然后我们分块处理出 fi,j 表示 [i,j1] 这段区间中任取一点和点 j 异或和的最大值,而用 gi,j 做个类似前缀和的操作,记录第 i 块的开头到点 j 这段区间中任意两点异或和最大值, gi,j 可以由 max(gi,j1,fi,j) 更新得到。当然这里其实没有必要多开一个 g 数组的,直接有序地在 f 数组上做就可以了。

但是 f 数组怎么得到呢?我们可以写一个可持久化字典树,然后 O(log2int) 查询一个数和一段区间中某数的最大/最小异或和。(这个查询对于写这道题的人应该很水了,不会的问我。)

分块后:
我们已经处理出了 g 数组,那么对于每次询问 [l,r] 我们都可以先找出 l 右边第一个块,然后这个块头到 r 的两点最大异或和已经在 g 数组中预处理出来了, l 到这个块头的部分我们枚举每个点,然后用之前维护完了的可持久化字典树查询区间中异或最大值更新本次答案。

啦。很详细了。

代码:

#include 
#include 
#include 
#include 
#include 
#define N 13000
#define LN 35
#define SN 115
#define T 31
#define ls son[x][0]
#define rs son[x][1]
using namespace std;

int n,m,sum[N];

int blocks,size,belong[N];
int from[N],to[N];

struct Functional_Trie
{
    int root[N],cnt;
    int son[N*LN][2],size[N*LN];

    bool a[LN];
    void add(int w,int id)
    {
        root[id]=++cnt,size[cnt]=1;
        int i,x=root[id],y=root[id-1];
        root[id]=x;
        for(i=0;i<=T;i++)a[i]=((w>>i)&1);
        for(i=T;i>=0;i--)
        {
            if(a[i])
            {
                ls=son[y][0],rs=++cnt;
                size[cnt]=size[son[y][1]]+1;
                x=rs,y=son[y][1];
            }
            else {
                rs=son[y][1],ls=++cnt;
                size[cnt]=size[son[y][0]]+1;
                x=ls,y=son[y][0];
            }
        }
    }
    int query(int last,int now,int w)
    {
        int i,x=root[now],y=root[last-1];
        for(i=0;i<=T;i++)a[i]=((w>>i)&1);
        int ans=0;
        for(i=T;i>=0;i--)
        {
            if(a[i])
            {
                if(size[ls]-size[son[y][0]])
                    x=ls,y=son[y][0],ans+=(1<else x=rs,y=son[y][1];
            }
            else {
                if(size[rs]-size[son[y][1]])
                    x=rs,y=son[y][1],ans+=(1<else x=ls,y=son[y][0];
            }
        }
        return ans;
    }
}trie;
int ans[SN][N];
int main()
{
    int i,j,k;
    int a,b,c;

    scanf("%d%d",&n,&m),n++;
    trie.add(0,1);
    for(i=2;i<=n;i++)
    {
        scanf("%d",&sum[i]);
        sum[i]^=sum[i-1];
        trie.add(sum[i],i);
    }
    size=sqrt(n);
    for(i=1;i<=n;i+=size)
    {
        from[++blocks]=i;
        for(j=0;j1;
    }
    for(i=1;i<=n;i++)
    {
        int k=belong[i];if(i==from[k])k--;
        for(j=1;j<=k;j++)
        {
            ans[j][i]=trie.query(from[j],i-1,sum[i]);
            ans[j][i]=max(ans[j][i],ans[j][i-1]);
        }
    }
    int l,r,lastans=0;
    while(m--)
    {
        scanf("%d%d",&a,&b);
        l=((long long)a+lastans)%(n-1)+1;
        r=((long long)b+lastans)%(n-1)+1;
        if(l>r)swap(l,r);r++;

        lastans=0,k=belong[l];
        if(l==from[k])lastans=ans[k][r];
        else if(k==belong[r])
        {
            for(i=l;ifor(j=i+1;j<=r;j++)
                lastans=max(lastans,sum[i]^sum[j]);
        }
        else {
            k++;
            lastans=ans[k][r];
            for(i=l;i1,r,sum[i]));
        }
        printf("%d\n",lastans);
    }
    return 0;
}

你可能感兴趣的:(可持久化字典树,分块,模板)