题目链接
题目大意:
给一段数,进行三种操作
1、将一段区间所有数减去ai&-ai
2、将一段区间所有数加上2^k<= ai <2^(k+1)
3、区间和
总体思路:
求区间和可以直接用普通线段树来维护,但是操作1和2都不是线段树支持的区间操作。
对于操作1,我们可以采取直接暴力更新,但是我们会发现一个数减去一定次数的lowbit就会变为0,在0上进行更新操作是没有意义的,所以定义一个falg=1表示这段区间所有数都为0,那么这段区间就不用被更新了。
对于操作2,我们发现每次加上2^k,其实就是将最高位乘以2,所以我们可以将一个数分为高位和低位两部分来处理。每次更新操作2,其实将区间高位整体乘以2,这样就支持线段操作了。
后面就是线段树的基本操作了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const long long mod=998244353;
int t;
int n,m;
int x;
int ch,l,r;
struct ty{
int l,r;
ll la,lb;//la表示高位,lb表示低位
int flag;//判断区间是不是都为0
ll lazy;//最高位乘以的数
ty():l(0),r(0),la(0),lb(0),flag(0),lazy(1){}
};
int a[100005],b[100005];
ty tr[100005*4];
void pushup(int u){
tr[u].la=(tr[u<<1].la+tr[u<<1|1].la)%mod;
tr[u].lb=(tr[u<<1].lb+tr[u<<1|1].lb)%mod;
tr[u].flag=tr[u<<1].flag&tr[u<<1|1].flag;
return ;
}
void build(int u,int l,int r){
tr[u].l=l; tr[u].r=r;
tr[u].lazy=1; tr[u].flag=0;
if(l==r){
tr[u].la=a[l]%mod;
tr[u].lb=b[l]%mod;
return ;
}
int mind=(l+r)>>1;
build(u<<1,l,mind);
build(u<<1|1,mind+1,r);
pushup(u);
return ;
}
void pushdown(int u){
if(tr[u].lazy>1){
tr[u<<1].la=tr[u<<1].la*tr[u].lazy%mod;
tr[u<<1|1].la=tr[u<<1|1].la*tr[u].lazy%mod;
tr[u<<1].lazy=tr[u<<1].lazy*tr[u].lazy%mod;
tr[u<<1|1].lazy=tr[u<<1|1].lazy*tr[u].lazy%mod;
tr[u].lazy=1;
}
return ;
}
void modify1(int u,int l,int r){
if(tr[u].l==tr[u].r){
if(tr[u].lb){
tr[u].lb-=(tr[u].lb&-tr[u].lb);
return ;
}
else{
tr[u].la=0;
tr[u].flag=1;
return ;
}
}
pushdown(u);
int mind=(tr[u].l+tr[u].r)>>1;
if(l<=mind&&!tr[u<<1].flag) modify1(u<<1,l,r);
if(r>mind&&!tr[u<<1|1].flag) modify1(u<<1|1,l,r);
pushup(u);
return ;
}
void modify2(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
tr[u].la=tr[u].la*2%mod;
tr[u].lazy=tr[u].lazy*2%mod;
return ;
}
pushdown(u);
int mind=(tr[u].l+tr[u].r)>>1;
if(l<=mind&&!tr[u<<1].flag) modify2(u<<1,l,r);
if(r>mind&&!tr[u<<1|1].flag) modify2(u<<1|1,l,r);
pushup(u);
return ;
}
ll query(int u,int l,int r){
if(tr[u].l>=l&&tr[u].r<=r){
return (tr[u].la+tr[u].lb)%mod;
}
pushdown(u);
int mind=(tr[u].l+tr[u].r)>>1;
ll ans=0;
if(l<=mind&&!tr[u<<1].flag) ans=(ans+query(u<<1,l,r))%mod;
if(r>mind&&!tr[u<<1|1].flag) ans=(ans+query(u<<1|1,l,r))%mod;
return ans;
}
int main(){
scanf(" %d",&t);
while(t--){
scanf(" %d",&n);
for(int i=1;i<=n;i++){
scanf(" %d",&x);
for(int j=33;j>=0;j--){
if((1ll<<j)<=x){//**记得为1ll**,不然1<<j爆int会为0导致错误
a[i]=1ll<<j;
b[i]=x-(1ll<<j);
break;
}
}
}
build(1,1,n);
scanf(" %d",&m);
for(int i=1;i<=m;i++){
scanf(" %d %d %d",&ch,&l,&r);
if(ch==1) printf("%lld\n",query(1,l,r));
else if(ch==2) modify1(1,l,r);
else modify2(1,l,r);
}
}
return 0;
}
京公网安备 11010502036488号