BZOJ2741: 【FOTILE模拟赛】L

题目:http://www.lydsy.com/JudgeOnline/problem.php?id=2741

分块+可持久化trie

f[i][j]表示第i块到第j个数的最大答案。可以通过n^1.5时间内维护出来。

然后对于询问就前面那一段暴力找和块的答案相比较就好了。

然后似乎一定要插一个0 。。。

#include<cstring>
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<set>
#include<cmath>
#define rep(i,l,r) for (int i=l;i<=r;i++)
#define down(i,l,r) for (int i=l;i>=r;i--)
#define clr(x,y) memset(x,y,sizeof(x))
#define maxn 20050
#define inf int(1e9)
#define maxd 30
#define mm 1000000007
#define ll long long
using namespace std;
int a[maxn];
int f[130][maxn],s[maxn*301][2],sum[maxn*301],root[maxn],pos[maxn];
int n,l,r,m,cnt,ans,len,num;
int read(){
    int x=0,f=1; char ch=getchar();
    while (!isdigit(ch)) {if (ch=='-') f=-1; ch=getchar();}
    while (isdigit(ch)) {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
void add(int d,int x,int &y,int val){
    y=++cnt; sum[y]=sum[x]+1; 
    if (d<0) return;
    s[y][0]=s[x][0]; s[y][1]=s[x][1];
    int p=(val>>d)&1;
    add(d-1,s[x][p],s[y][p],val);
}
int ask(int d,int x,int y,int val){
    if (d<0) return 0;
    int p=(val>>d)&1;
    if (sum[s[y][p^1]]-sum[s[x][p^1]]>0) return (1<<d)+ask(d-1,s[x][p^1],s[y][p^1],val);
    else return ask(d-1,s[x][p],s[y][p],val);
}
void getans(int l,int r){
    ans=0;
    int lx=pos[l],rx=pos[r];
    if (lx<rx) ans=f[lx+1][r];
    rep(i,l,min(lx*len,r)) ans=max(ans,ask(maxd,root[l],root[r+1],a[i]));
    printf("%d\n",ans);
}
int main(){
    n=read(); m=read();
    len=sqrt(n);
    rep(i,1,n) a[i]=read(),a[i]=a[i]^a[i-1],pos[i]=i/len+1; 
    rep(i,0,n) add(maxd,root[i],root[i+1],a[i]);
    num=n/len+1;
    rep(i,1,num) {
        int now=(i-1)*len;
        rep(j,now,n) f[i][j]=max(f[i][j-1],ask(maxd,root[now],root[j+1],a[j]));
    }
    ans=0;
    rep(i,1,m){
        int x=read(),y=read();
        x=((ll)x+ans)%n+1; y=((ll)y+ans)%n+1;
        l=min(x,y); r=max(x,y);
        getans(l-1,r);
    }
    return 0;
}

 

posted on 2015-12-22 21:35  ctlchild  阅读(158)  评论(0编辑  收藏  举报

导航