蓝书(算法竞赛进阶指南)刷题记录——BZOJ2741 【FOTILE模拟赛】L(分块+可持久化0-1 Trie)

题目:BZOJ2741.
题目大意:给定一个长度为 n n n的序列 a a a,并有 M M M组询问 l , r l,r l,r,表示询问当 l ≤ i ≤ j ≤ r l \leq i\leq j \leq r lijr时, a [ i ]   x o r   a [ i + 1 ]   x o r   . . .   x o r   a [ j ] a[i]\,xor\,a[i+1]\,xor\,...\,xor\,a[j] a[i]xora[i+1]xor...xora[j]的最大值.
1 ≤ n ≤ 1.2 ∗ 1 0 4 , 1 ≤ m ≤ 6000 1\leq n\leq 1.2*10^4,1\leq m\leq 6000 1n1.2104,1m6000.

回忆这种题的套路,我们发现这道题绝对要前缀xor一下,变成查询两个数的xor和最大.又由于是查询区间,所以上个可持久化0-1 Trie.一看两个端点都不确定,那就考虑一个朴素的暴力,暴力枚举一个端点,然后找另一个端点…时间复杂度 O ( 31 m n ) O(31mn) O(31mn)完美TLE(虽然我没试过)…

考虑如何优化,很容易想到万能分块.设每个块大小为siz,分成 n s i z \frac{n}{siz} sizn个块,预处理出第i个块到第j个块之间的答案f[i][j],然后暴力搞边上的块.预处理时间复杂度 O ( 31 n n s i z ) O(31n\frac{n}{siz}) O(31nsizn),总查询时间复杂度 O ( 31 m ∗ s i z ) O(31m*siz) O(31msiz),平衡一下取 s i z = n m siz=\frac{n}{\sqrt{m}} siz=m n可以做到 O ( 31 n m ) O(31n\sqrt{m}) O(31nm ).

代码如下(没怎么写过分块比较丑请见谅QAQ):

#include<bits/stdc++.h>
  using namespace std;
 
#define Abigail inline void
typedef long long LL;
 
const int N=12000,B=500,C=31;
 
struct Trie{
  int s[2],cnt;
}tr[N*(C+2)+9];      //一定不能只开N*C的数组,因为可持久化Trie数的节点个数为N*(C+2),这是由于总共C+1位,可持久化Trie还要多建几个N个根 
int cn,cr,rot[N+9];
 
void Trie_build(){cr=cn=0;}
 
void Trie_insert(int a){ 
  rot[++cr]=++cn;
  int x=rot[cr],x0=rot[cr-1];
  for (int i=C;i>=0;--i){
    tr[x]=tr[x0];++tr[x].cnt; 
    tr[x].s[a>>i&1]=++cn;x=cn;
    x0=tr[x0].s[a>>i&1];
  }
  tr[x]=tr[x0];++tr[x].cnt;
}
 
int Trie_query(int l,int r,int a){
  int xl=rot[l-1],xr=rot[r],ans=0,t;
  for (int i=C;i>=0;--i){
    t=a>>i&1;
    if (tr[tr[xr].s[t^1]].cnt-tr[tr[xl].s[t^1]].cnt>0)
      ans|=1<<i,xl=tr[xl].s[t^1],xr=tr[xr].s[t^1];
    else xl=tr[xl].s[t],xr=tr[xr].s[t];
  }
  return ans;
} 
 
int n,m,s[N+9],mod;
struct Block{
  int l,r;
}bl[B+9];
int siz,cb,f[B+9][B+9],bel[N+9];
 
void Block_build(){
  siz=n/sqrt(m);
  if (n/siz>B) siz=n/B;      //防止块数太多导致溢出
  for (bl[cb=0].r=0;bl[cb].r<n;++cb) bl[cb+1].l=bl[cb].r+1,bl[cb+1].r=bl[cb].r+siz;
  bl[cb].r=n;
  for (int i=1;i<=n;++i)
    bel[i]=bl[bel[i-1]].r<i?bel[i-1]+1:bel[i-1];
  for (int i=1;i<=cb;++i)
    for (int j=i;j<=cb;++j){
      f[i][j]=f[i][j-1];
      for (int k=bl[j].l;k<=bl[j].r;++k)
        f[i][j]=max(f[i][j],Trie_query(bl[i].l,bl[j].r,s[k]));
    } 
}
 
int Block_query(int l,int r){
  int ans=0,lb=bel[l],rb=bel[r];
  if (lb+1>=rb){
    for (int i=l;i<=r;++i)
      ans=max(ans,Trie_query(l,r,s[i]));
    return ans;
  }
  for (int i=l;i<=bl[lb].r;++i)
    ans=max(ans,Trie_query(l,r,s[i]));
  for (int i=bl[rb].l;i<=r;++i)
    ans=max(ans,Trie_query(l,r,s[i]));
  return max(ans,f[lb+1][rb-1]);
}
 
Abigail into(){
  scanf("%d%d",&n,&m);
  mod=n;++n;
  for (int i=2;i<=n;++i){
    scanf("%d",&s[i]);
    s[i]^=s[i-1];
  }
}
 
Abigail work(){
  Trie_build();
  for (int i=1;i<=n;++i)
    Trie_insert(s[i]);
  Block_build();
}
 
Abigail getans(){
  int x,y,ans=0,l,r;
  for (int i=1;i<=m;++i){
    scanf("%d%d",&x,&y);
    l=min(((LL)x+ans)%mod+1,((LL)y+ans)%mod+1);
    r=max(((LL)x+ans)%mod+1,((LL)y+ans)%mod+1);
    printf("%d\n",ans=Block_query(l,r+1));
  }
}
 
int main(){
  into();
  work();
  getans();
  return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值