bzoj 2741: 【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 ).
其中lastans是上次询问的答案,一开始为0。

Input

第一行两个整数N和M。
第二行有N个正整数,其中第i个数为Ai,有多余空格。
后M行每行两个数x,y表示一对询问。

Output

 

共M行,第i行一个正整数表示第i个询问的结果。

Sample Input

3 3
1 4 3
0 1
0 1
4 3


Sample Output

5
7
7

HINT



HINT

N=12000,M=6000,x,y,Ai在signed longint范围内。


分块+可持久化trie

用f[i][j]表示第i块开头到位置j的最大ans

f[i][j]=max(f[i][j-1],ask(head[i],j-1,a[j]))

这里处理是nsqrt(n)logn

然后每次询问的时候把整块的一起处理

再枚举前面部分的位置,更新ans即可

#include<cmath>
#include<cstdio>
#include<string>
#include<cstring>
using namespace std;
struct tree
{
     int l,r;
     int ll,rr;
}tr[5000001];
int root[600001];
long long px[32];
int tot;
inline int add(int p,int d,int dep)
{
     if(dep==31)
          return 0;
     if(d>=px[dep])
     {
     	  tot++;
     	  int pp=tot;
          tr[pp].l=tr[p].l;
          tr[pp].ll=tr[p].ll;
          tr[pp].r=add(tr[p].r,d-px[dep],dep+1);
          tr[pp].rr=tr[p].rr+1;
          return pp;
     }
     else
     {
     	  tot++;
     	  int pp=tot;
          tr[pp].l=add(tr[p].l,d,dep+1);
          tr[pp].ll=tr[p].ll+1;
          tr[pp].r=tr[p].r;
          tr[pp].rr=tr[p].rr;
          return pp;
     }
}
inline int ask(int l,int r,int x,int dep)
{
	 if(dep==31)
	      return 0;
     if(x>=px[dep])
     {
          if(tr[r].ll-tr[l].ll>0)
               return px[dep]+ask(tr[l].l,tr[r].l,x-px[dep],dep+1);
          else
               return ask(tr[l].r,tr[r].r,x-px[dep],dep+1);
     }
     else
     {
          if(tr[r].rr-tr[l].rr>0)
               return px[dep]+ask(tr[l].r,tr[r].r,x,dep+1);
          else
               return ask(tr[l].l,tr[r].l,x,dep+1);
     }
}
int a[100001];
int x[100001];
int belong[100001];
int head[1001];
int f[1001][20001];
int main()
{
//	 freopen("data.in","r",stdin);
//	 freopen("data.out","w",stdout);
     long long n;
	 int m;
     scanf("%lld%d",&n,&m);
     int i,j;
     px[0]=1;
     for(i=1;i<=30;i++)
          px[i]=px[i-1]*2;
	 for(i=0;i<=15;i++)
	 {
	      int t=px[i];
	      px[i]=px[30-i];
	      px[30-i]=t;
	 }
	 root[0]=1;
	 add(0,0,0);
     for(i=1;i<=n;i++)
     {
          scanf("%lld",&x[i]);
          a[i]=(a[i-1]^x[i]);
          root[i]=tot+1;
          add(root[i-1],a[i],0);
     }
     int nt=sqrt(n);
     int nx=0;
     for(i=1;i<=n;i++)
     {
          belong[i]=(i-1)/nt+1;
          if(belong[i]!=belong[i-1])
          {
               nx++;
               head[belong[i]]=i;
          }
     }
     head[nx+1]=n+1;
     for(i=1;i<=nx;i++)
     {
     	  f[i][head[i]]=x[head[i]];
          for(j=head[i]+1;j<=n;j++)
          {
          	   int rt=head[i]-2;
			   if(rt<0)
			        rt=0;
			   else
			        rt=root[rt];
               f[i][j]=max(f[i][j-1],ask(rt,root[j-1],a[j],0));
          }
     }
     long long s,t;
     long long last=0; 
     for(i=1;i<=m;i++)
     {
     	  scanf("%lld%lld",&s,&t);
     	  int ss=(s+last)%n+(long long)1,tt=(t+last)%n+(long long)1;
     	  s=min(ss,tt);
     	  t=max(ss,tt);
     /*	  if(s==t)
     	  {
     	       printf("%d\n",x[s]);
     	       continue;
     	  }*/
     	  int nxt=belong[s];
     	  if(head[nxt]!=s)
     	       nxt++;
          int ans=f[nxt][t];
          for(j=s;j<=min(head[nxt]-1,(int)t);j++)
          {
               ans=max(ans,ask(root[s-1],root[t],a[j-1],0));
          }
          printf("%lld\n",ans);
          last=ans;
     }
     return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值