【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;
}
时间: 2024-08-09 17:20:33

【BZOJ2741】【FOTILE模拟赛】L 可持久化字典树+分块的相关文章

BZOJ2741[FOTILE模拟赛]L

Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y): l=min(((x+lastans)mod N)+1,((y+lastans)mod N)+1). r=max(((x+lastans)mod N)+1,((y+lastans)mod N)+1).

【BZOJ2741】【块状链表+可持久化trie】FOTILE模拟赛L

Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y): l = min ( ((x+lastans) mod N)+1 , ((y+lastans) mod N)+1 ).r = max ( ((x+lastans) mod N)+1 , ((y+last

bzoj 2741: 【FOTILE模拟赛】L 分塊+可持久化trie

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 1116  Solved: 292[Submit][Status] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一个询问(x,y):

bzoj2741: 【FOTILE模拟赛】L

2741: [FOTILE模拟赛]L Time Limit: 15 Sec  Memory Limit: 162 MBSubmit: 2679  Solved: 766[Submit][Status][Discuss] Description FOTILE得到了一个长为N的序列A,为了拯救地球,他希望知道某些区间内的最大的连续XOR和. 即对于一个询问,你需要求出max(Ai xor Ai+1 xor Ai+2 ... xor Aj),其中l<=i<=j<=r. 为了体现在线操作,对于一

【BZOJ】【2741】【FOTILE模拟赛】L

可持久化Trie+分块 神题……Orz zyf & lyd 首先我们先将整个序列搞个前缀异或和,那么某一段的异或和,就变成了两个数的异或和,所以我们就将询问[某个区间中最大的区间异或和]改变成[某个区间中 max(两个数的异或和)] 要是我们能将所有[l,r]的答案都预处理出来,那么我们就可以O(1)回答了:然而我们并不能. 一个常见的折中方案:分块! 这里先假设我们实现了一个神奇的函数ask(l,r,x),可以帮我们求出[l,r]这个区间中的数,与x最大的异或值. 我们不预处理所有的左端点,我

codechef Xor Queries (可持久化字典树)

题目链接:codechef Xor Queries 题意: 题解: 一棵可持久化字典树就行了. 1 #include<bits/stdc++.h> 2 #define F(i,a,b) for(int i=(a);i<=(b);++i) 3 using namespace std; 4 5 const int N=5e5+7; 6 struct Node{int son[2],cnt;}ch[N*40]; 7 int root[N],cnt,ed,n; 8 9 void ins(int

Codeforces 706D Vasiliy&#39;s Multiset(可持久化字典树)

[题目链接] http://codeforces.com/problemset/problem/706/D [题目大意] 要求实现一个集合中的三个操作,1:在集合中加入一个元素x,2:从集合中删除一个元素x(保证x存在),3:要求从集合中选出一个数,使得其与给出的数x的异或值最大,输出这个异或值. [题解] 可以将所有的以二进制形式存在01字典树上,删除即插入权值为-1的二进制串,对于异或值最大的操作,我们只要在字典树上按位贪心,从最高位开始尽量保证该位存在最后就能得到答案.写代码的时候直接写了

hdu 6191 Query on A Tree(dfs序+可持久化字典树)

题目链接:hdu 6191 Query on A Tree 题意: 给你一棵树,每个节点有一个值,现在有q个询问,每个询问 询问一个u x,问以u为根的子树中,找一个节点,使得这个节点的值与x异或的值最大,输出那个最大的值. 题解: dfs序和一棵可持久化字典树就搞定了. 1 #include<bits/stdc++.h> 2 #define mst(a,b) memset(a,b,sizeof(a)) 3 #define F(i,a,b) for(int i=a;i<=b;++i) 4

bzoj3166: [Heoi2013]Alo 可持久化字典树

左右两边的比i大的最近的两个值.然后可持久化字典树即可. #include<bits/stdc++.h> using namespace std; int maxn=0,n,root[1600000],a[50010],cnt=0,l[1600000],r[1600000],p1[50010][25],p2[50010][25],sum[1600000],ans=0,pans=0,l1[50010],r1[50010],l2[50010],r2[50010]; void add(int &am