P8421 解题报告

好题。

考虑离线:

  • Kira:统计一个区间 \([l,r]\) 的所有子区间权值和可以转化为 \(f_{r,r}-f_{r,l-1}\),其中 \(f_{i,j}\) 表示 \(l\le i,r \le j\) 的区间 \([l,r]\) 的权值和。

然后考虑已知 \(f_r\) 快速计算 \(f_{r+1}\)

对于 \(f_{r,i} \to f_{r+1,i}\),其增加了 \([i,r+1]\)\(\forall i\in[1,r+1]\) 的区间的权值。

按位与,按位或,\(\gcd\),很难不让人想到势能分析。

不难得出,\(f_{r,i} \to f_{r+1,i}\) 时,必定存在一个 \(p\in[1,r+1]\),使得:\(\forall i<p\)\([i,r+1]\) 的权值和 \([i,r]\) 相同,且 \(\forall i \in[p,r+1]\)\([i,r+1]\) 的权值与 \([i,r]\) 不同。

而且这个 \(p\)\(r+1\) 的距离还很近,是 \(\mathcal{O(\log n)}\) 级别的。

这启发我们对于 \([1,p)\) 的新增权值用懒标记的思想维护,\([p,r+1]\) 的暴力修改。

具体地,我们先将询问离线按 \(r\) 升序排序,然后对于每个 \(r\),暴力地找到对应的 \(p\),对 \([1,r]\)\(p\) 劈开分成两部分处理。我们记录懒标记的标记时间戳,\([1,p)\) 段不用管,\([p,r+1]\) 段暴力修改时直接更新懒标记和对应的标记时刻,查询时用当前时刻减去标记时刻即可得知懒标记的作用时长。

复杂度 \(\mathcal{O(n\log V + m\log m)}\)

细节看代码。

const int N=1e6+3,M=5e6+3;
int n,m,a[N],b[N],c[N],t[N];
sd array<int,3>q[M];
ui s[N],ans[M],tg[N];
il ui _Q(int x,ui tt){return s[x]+tg[x]*(tt-t[x]);}
il void Solve()
{
  rd(n),rd(m);
  for(int i=1;i<=n;++i) rd(a[i]);
  for(int i=1;i<=n;++i) rd(b[i]);
  for(int i=1;i<=n;++i) rd(c[i]);
  for(int i=1,l,r;i<=m;++i) rd(l),rd(r),q[i]={r,l,i};
  sd stable_sort(q+1,q+m+1);
  for(int r=1,i=0,pos;r<=n;++r)
  {
    for(pos=r;pos-1;--pos)
    {
      if((a[pos]&a[pos-1])==a[pos-1]&&(b[pos]|b[pos-1])==b[pos-1]&&sd __gcd(c[pos],c[pos-1])==c[pos-1]) break;
      a[pos-1]&=a[pos],b[pos-1]|=b[pos],c[pos-1]=sd __gcd(c[pos],c[pos-1]);
    }
    s[r]=_Q(r-1,r);
    for(int j=pos;j<=r;++j) s[j]=_Q(j,r),tg[j]=tg[j-1]+1ull*a[j]*b[j]*c[j],t[j]=r;
    for(;i<m&&r==q[i+1][0];++i,ans[q[i][2]]=_Q(q[i][0],r+1)-_Q(q[i][1]-1,r+1));
  }
  for(int i=1;i<=m;++i) wrt(ans[i],'\n');
  return;
}

\(\color{green}{\checkmark}\)

posted @ 2023-10-13 21:04  BK0717BK0717  阅读(50)  评论(0)    收藏  举报