YYR字符串 异或 [可持久化Trie][分块][回滚莫队]

异或(xor.c/cpp/pas)

2.1 题目描述
给出 n 个数,Q次询问,每次问[l,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 )
2.2 输入格式
第一行为两个整数n,m,分别表示数的个数和询问次数。
接下来一行 n个数,再接下来 m行,每行两个数 x,y,表示给出询问(x,y),通过上述操作得到l和r,查询[l,r]中最大连续异或和。
2.3 输出格式
输出m行,每行一个整数表示该次询问的答案。
2.4 样例输入
3 3
1 4 3
0 1
0 1
4 3
2.5 样例输出
5
7
7
2.6 数据范围与约定
对于30%的数据,n<=500,Q<=500。
对于100%的数据,n<=12000 , Q<=6000 , 给出的数均在signed longint范围内,且均为非负数。

题解

一眼看出BZOJ2741原题。。。回滚莫队水过。

分块+可持久化Trie树贪心。为了方便大家看,将讲稿粘贴于此。
将 n 个数分成sqrt(n)个块。考虑用 w[i][j] 表示从第 i 个块开头元素到第 j 个元素这个区间中,最大连续异或和。建可持久化Trie树并且预处理出w数组。预处理复杂度为 O(n * sqrt(n) * 位数)。
查询[l,r]时,令 p 为 l 以右第一个块开头元素,那么首先可以直接得到 p 到 r 区间的答案。再考虑上 [l,p-1] 区间中的元素,逐个在可持久化Trie上贪心即可。查询总复杂度为O(Q * sqrt(n) * 位数)。

#include  
#include  
#include  
#include  
#include  
#include  
#define ll long long  
#define N 20000  
#define M 800000  
using namespace std;  
int n,m,tot,block,num;  
int a[N],rt[N],pos[N],id[M],t[M][2],f[400][N];  
inline int read(){  
    int x=0,f=1;char ch=getchar();  
    while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}  
    while (ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}  
    return x*f;  
}
inline void insert(int pre,int k,int x){
    register int now=rt[k]=++tot;id[tot]=k;  
    pre=rt[pre];  
    for(register int i=30;i>=0;--i){  
        register int j=(x>>i)&1;  
        t[now][j^1]=t[pre][j^1];  
        t[now][j]=++tot;id[tot]=k;  
        now=t[now][j];pre=t[pre][j];  
    }  
}  
inline int query(int l,int r,int x){
    int ans=0,tmp=rt[r];  
    for(register int i=30;i>=0;i--){  
        if(id[tmp]break;  
        register int j=((x>>i)&1)^1;  
        if(id[t[tmp][j]]>=l)ans|=(1<else j^=1
        tmp=t[tmp][j];  
    }
    return ans;  
}  
int main(){
    freopen("xor.in","r",stdin);
    freopen("xor.out","w",stdout);
    n=read();m=read();  
    block=int(sqrt(n));num=n/block+(n%block!=0);  
    for(register int i=1;i<=n;++i)pos[i]=(i-1)/block+1;  
    id[0]=-1;insert(0,0,0);  
    for(register int i=1;i<=n;++i)a[i]=a[i-1]^read();  
    for(register int i=1;i<=n;i++)insert(i-1,i,a[i]);
    for(register int i=1;i<=num;++i)
        for(register int j=(i-1)*block+1;j<=n;++j)  
            f[i][j]=max(f[i][j-1],query((i-1)*block+1,j,a[j]));  
    register int ans=0;  
    while(m--){  
        ll l=read(),r=read();
        l=((ll)ans+l)%n+1;
        r=((ll)ans+r)%n+1;  
        if(l>r)swap(l,r);  
        ans=0;l--;
        if(pos[l]==pos[r]){  
            for(register int i=l;i<=r;++i) 
                ans=max(ans,query(l,r,a[i]));  
        }else{  
            ans=f[pos[l]+1][r];  
            for(register int i=l;i<=pos[l]*block;++i)
                ans=max(ans,query(l,r,a[i]));  
        }  
        printf("%d\n",ans);  
    }
    return 0;  
}

对于这道题来说,最大的看点在于如何处理好与平时分块不同的预处理方法。一般的分块处理的只是块内的信息,但是这中分块方法处理了块与块之间的联系。

YYR字符串 异或 [可持久化Trie][分块][回滚莫队]_第1张图片

你可能感兴趣的:(字符串,可持久化Trie,分块,莫队)