\(\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;
}