\(\text{Problem}:\)Sonya and Bitwise OR
\(\text{Solution}:\)
分析一下 OR 的性质。对于左端点 \(l\) 固定的区间,其前缀至多只会有 \(\lceil \log_{2}V\rceil\) 个不同的取值,且每种取值都是连续的。当右端点固定时也是同理。
那么对于每个区间 \([l,r]\),维护其前缀与后缀每种不同取值的起始位置与长度。合并时只需枚举左儿子和右儿子的不同取值,在 \(O(20^{2})\) 的复杂度内暴力求出答案,而更新其前缀与后缀的信息也非常容易。
总时间复杂度 \(O(n\log n\log^{2} V)\)。
\(\text{Code}:\)
#include <bits/stdc++.h> #pragma GCC optimize(3) //#define int long long #define ri register #define mk make_pair #define fi first #define se second #define pb push_back #define eb emplace_back #define is insert #define es erase #define vi vector<int> #define vpi vector<pair<int,int>> using namespace std; const int N=100010; inline int read() { int s=0, w=1; ri char ch=getchar(); while(ch<'0'||ch>'9') { if(ch=='-') w=-1; ch=getchar(); } while(ch>='0'&&ch<='9') s=(s<<3)+(s<<1)+(ch^48), ch=getchar(); return s*w; } int n,m,X,a[N]; #define lc (x<<1) #define rc (x<<1|1) struct Node { vpi pre,nxt; long long sum; inline Node() { sum=0; } }w[N<<2],zero; inline Node Merge(Node x,Node y) { Node res; res.sum=x.sum+y.sum; for(auto i:x.nxt) { for(auto j:y.pre) { if((i.fi|j.fi)>=X) res.sum+=1ll*i.se*j.se; } } res.pre=x.pre; for(auto i:y.pre) { if((i.fi|res.pre.back().fi)==res.pre.back().fi) res.pre.back().se+=i.se; else res.pre.eb(mk((res.pre.back().fi|i.fi),i.se)); } res.nxt=y.nxt; for(auto i:x.nxt) { if((i.fi|res.nxt.back().fi)==res.nxt.back().fi) res.nxt.back().se+=i.se; else res.nxt.eb(mk((res.nxt.back().fi|i.fi),i.se)); } return res; } void Build(int x,int l,int r) { if(l==r) { w[x].pre.eb(mk(a[l],1)); w[x].nxt.eb(mk(a[l],1)); w[x].sum=(a[l]>=X); return; } int mid=(l+r)/2; Build(lc,l,mid); Build(rc,mid+1,r); w[x]=Merge(w[lc],w[rc]); } void UpDate(int pos,int l,int r,int x,int k) { if(l==r) { w[x].pre.clear(), w[x].nxt.clear(); w[x].pre.eb(mk(k,1)), w[x].nxt.eb(mk(k,1)); w[x].sum=(k>=X); return; } int mid=(l+r)/2; if(pos<=mid) UpDate(pos,l,mid,lc,k); else UpDate(pos,mid+1,r,rc,k); w[x]=Merge(w[lc],w[rc]); } Node Ask(int u,int v,int l,int r,int x) { if(l>v||r<u) return zero; if(l>=u&&r<=v) return w[x]; int mid=(l+r)/2; if(u>mid) return Ask(u,v,mid+1,r,rc); if(v<=mid) return Ask(u,v,l,mid,lc); return Merge(Ask(u,mid,l,mid,lc),Ask(mid+1,v,mid+1,r,rc)); } #undef lc #undef rc signed main() { n=read(), m=read(), X=read(); for(ri int i=1;i<=n;i++) a[i]=read(); Build(1,1,n); for(ri int i=1;i<=m;i++) { int opt=read(); if(opt==1) { int x,y; x=read(), y=read(); UpDate(x,1,n,1,y); } else { int l,r; l=read(), r=read(); printf("%lld\n",Ask(l,r,1,n,1).sum); } } return 0; }