有一个长度为
n " role="presentation"> 的数组{ a } " role="presentation">,有m " role="presentation"> 次操作,又给定一个数x " role="presentation">,有两类操作:
1 i y将" role="presentation"> 改为 a i y " role="presentation">;2 l r查询有多少个区间[ L , R ] " role="presentation"> 满足" role="presentation"> 的按位或 a L … R " role="presentation"> 大于等于 o r x " role="presentation">。
1 ≤ n , m ≤ 10 5 ; 0 ≤ a i , x , y ≤ " role="presentation">。 2 20
先考虑如果只有询问操作怎么做。
那可以算出这段区间的中点开始,算出
那么可以通过双指针来求出每一个符合条件的区间,如果改为多次询问就用树状数组记下来,一次
那么可以在线段树中维护区间内的前后缀
总结:
最开始的 CDQ 想法大体方向是正确的,和正解都利用了分治。但是存在修改操作后,对区间分治就不能够在 CDQ 上进行,必须另寻他路。
那么接下来就应当考虑在线解决这个问题,这道题的区间是可以合并的,而平衡复杂度的思想就让我们想到了线段树。
最后这个经典的
- #define Maxn 100005
- int n,m,X;
- int a[Maxn];
- struct SUB
- {
- SUB(int Val=0,int Pl=0,int Pr=0):val(Val),pl(Pl),pr(Pr){}
- int val,pl,pr;
- };
- SUB tpre[100],tsuf[100];
- struct TREE
- {
- ll sum;
- vector pre,suf;
- TREE(){ sum=0,pre.clear(),suf.clear(); }
- inline void push(int x,int Nu)
- {
- pre.clear(),suf.clear(),sum=(x>=X),
- pre.pb(SUB(x,Nu,Nu)),suf.pb(SUB(x,Nu,Nu));
- }
- }tree[Maxn<<2];
- inline TREE merge(TREE L,TREE R)
- {
- int ppre=0,psuf=0,tl=L.pre.back().val,tr=R.suf.front().val;
- for(SUB v:L.pre) tpre[++ppre]=v;
- for(SUB v:R.pre) tpre[++ppre]=SUB(v.val|tl,v.pl,v.pr);
- for(SUB v:L.suf) tsuf[++psuf]=SUB(v.val|tr,v.pl,v.pr);
- for(SUB v:R.suf) tsuf[++psuf]=v;
- tpre[ppre+1]=SUB(-1,0,0),tsuf[psuf+1]=SUB(-1,0,0);
- TREE ret; ret.sum=L.sum+R.sum;
- for(int nl=0,nr=0,sl=L.suf.size()-1,sr=R.pre.size()-1;nl<=sl;nl++)
- {
- while(nr<=sr && (L.suf[nl].val|R.pre[nr].val)
- if(nr>sr) break;
- ret.sum+=1ll*(R.pre[sr].pr-R.pre[nr].pl+1)*
- (L.suf[nl].pr-L.suf[nl].pl+1);
- }
- for(int i=2,Last=0;i<=ppre+1;i++) if(tpre[i].val!=tpre[i-1].val)
- assert(tpre[Last+1].val==tpre[i-1].val),
- ret.pre.pb(SUB(tpre[i-1].val,tpre[Last+1].pl,tpre[i-1].pr)),Last=i-1;
- for(int i=2,Last=0;i<=psuf+1;i++) if(tsuf[i].val!=tsuf[i-1].val)
- assert(tsuf[Last+1].val==tsuf[i-1].val),
- ret.suf.pb(SUB(tsuf[i-1].val,tsuf[Last+1].pl,tsuf[i-1].pr)),Last=i-1;
- assert(ret.pre.size()<=30 && ret.suf.size()<=30);
- return ret;
- }
- void build(int p,int nl,int nr)
- {
- if(nl==nr) { tree[p].push(a[nl],nl); return; }
- int mid=(nl+nr)>>1;
- build(p<<1,nl,mid),build(p<<1|1,mid+1,nr);
- tree[p]=merge(tree[p<<1],tree[p<<1|1]);
- }
- void change(int p,int nl,int nr,int x,int k)
- {
- if(nl==nr) { tree[p].push(k,x); return; }
- int mid=(nl+nr)>>1;
- if(mid>=x) change(p<<1,nl,mid,x,k);
- else change(p<<1|1,mid+1,nr,x,k);
- tree[p]=merge(tree[p<<1],tree[p<<1|1]);
- }
- TREE query(int p,int nl,int nr,int l,int r)
- {
- if(nl>=l && nr<=r) return tree[p];
- int mid=(nl+nr)>>1;
- if(mid>=l && mid
- return merge(query(p<<1,nl,mid,l,r),query(p<<1|1,mid+1,nr,l,r));
- else if(mid>=l) return query(p<<1,nl,mid,l,r);
- else return query(p<<1|1,mid+1,nr,l,r);
- }
- int main()
- {
- n=rd(),m=rd(),X=rd();
- for(int i=1;i<=n;i++) a[i]=rd();
- build(1,1,n);
- for(int i=1,opt,x,y;i<=m;i++)
- {
- opt=rd(),x=rd(),y=rd();
- if(opt==1) change(1,1,n,x,y);
- else printf("%lld\n",query(1,1,n,x,y).sum);
- }
- return 0;
- }
