大意: 给定序列$a$, 给定整数$x$. 两种操作(1)单点修改 (2)给定区间$[l,r]$,求有多少子区间满足位或和不少于$x$.
假设不带修改. 固定右端点, 合法区间关于左端点单调的. 可以预处理出最近的合法的左端点位置.那么每次询问答案就为$sumlimits_{substack{pre[i]ge l\ l le ile r}}(pre[i]-l+1)$. 用二维数点的方法处理即可.
带修改的话, 关键是要注意到或和最多改变$20$次, 线段树记录下来改变的位置, 暴力合并即可.
#include <iostream> #include <iostream> #include <algorithm> #include <cstdio> #include <math.h> #include <set> #include <map> #include <queue> #include <string> #include <string.h> #include <bitset> #define REP(i,a,n) for(int i=a;i<=n;++i) #define PER(i,a,n) for(int i=n;i>=a;--i) #define hr putchar(10) #define pb push_back #define lc (o<<1) #define rc (lc|1) #define mid ((l+r)>>1) #define ls lc,l,mid #define rs rc,mid+1,r #define x first #define y second #define io std::ios::sync_with_stdio(false) #define endl ' ' #define DB(a) ({REP(__i,1,n) cout<<a[__i]<<' ';hr;}) using namespace std; typedef long long ll; typedef pair<int,int> pii; const int N = 1e5+10; int n,m,X,a[N]; struct _ { int lnum,rnum,x,L,R; ll ans; pii l[22],r[22]; _ () {} _ (int lnum,int rnum,int x,int L,int R,ll ans):lnum(lnum),rnum(rnum),x(x),L(L),R(R),ans(ans) {} _ (int pos, int val) { L=R=l[1].y=r[1].y=pos; l[1].x=r[1].x=x=val; ans=(val<X); lnum=rnum=1; } _ operator + (const _& rhs) const { _ ret(lnum,rhs.rnum,x|rhs.x,L,rhs.R,ans+rhs.ans); memcpy(ret.l,l,sizeof l); memcpy(ret.r,rhs.r,sizeof r); for (int i=rnum,j=0; i; --i) { while (j<rhs.lnum&&(r[i].x|rhs.l[j+1].x)<X) ++j; ret.ans += (ll)(r[i].y-(i<rnum?r[i+1].y:L-1))*((j<rhs.lnum?rhs.l[j+1].y:rhs.R+1)-rhs.L); } REP(i,1,rhs.lnum) if ((rhs.l[i].x|x)!=ret.l[ret.lnum].x) { (ret.l[++ret.lnum]=rhs.l[i]).x |= x; } REP(i,1,rnum) if ((r[i].x|rhs.x)!=ret.r[ret.rnum].x) { (ret.r[++ret.rnum]=r[i]).x |= rhs.x; } return ret; } } tr[N<<2]; void build(int o, int l, int r) { if (l==r) tr[o]=_(l,a[l]); else build(ls),build(rs),tr[o]=tr[lc]+tr[rc]; } void update(int o, int l, int r, int x, int v) { if (l==r) tr[o]=_(x,v); else { mid>=x?update(ls,x,v):update(rs,x,v); tr[o]=tr[lc]+tr[rc]; } } _ query(int o, int l, int r, int ql, int qr) { if (ql<=l&&r<=qr) return tr[o]; if (mid>=qr) return query(ls,ql,qr); if (mid<ql) return query(rs,ql,qr); return query(ls,ql,qr)+query(rs,ql,qr); } int main() { scanf("%d%d%d", &n, &m, &X); REP(i,1,n) scanf("%d", a+i); build(1,1,n); while (m--) { int op,x,y; scanf("%d%d%d", &op, &x, &y); if (op==1) update(1,1,n,x,y); else printf("%lld ",(y-x+1ll)*(y-x+2)/2-query(1,1,n,x,y).ans); } }