码迷,mamicode.com
首页 > 其他好文 > 详细

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

时间:2015-03-20 22:07:44      阅读:223      评论:0      收藏:0      [点我收藏+]

标签:bzoj2741   fotile模拟赛   l   可持久化字典树   分块   

广告:

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

题解:

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

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

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

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

啦。很详细了。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#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<<i);
                else x=rs,y=son[y][1];
            }
            else {
                if(size[rs]-size[son[y][1]])
                    x=rs,y=son[y][1],ans+=(1<<i);
                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;j<size&&(i+j<=n);j++)
            belong[i+j]=blocks;
        to[blocks]=i+j-1;
    }
    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;i<r;i++)for(j=i+1;j<=r;j++)
                lastans=max(lastans,sum[i]^sum[j]);
        }
        else {
            k++;
            lastans=ans[k][r];
            for(i=l;i<min(from[k],r);i++)
                lastans=max(lastans,trie.query(i+1,r,sum[i]));
        }
        printf("%d\n",lastans);
    }
    return 0;
}

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

标签:bzoj2741   fotile模拟赛   l   可持久化字典树   分块   

原文地址:http://blog.csdn.net/vmurder/article/details/44496739

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!