题意:输入给出包含n个数的数组,和m次询问,询问包含两种,1、对区间[l,r]中的每一位数都加上一个lowbit(ai),2、询问[l,r]中数组和
思路:这题不难想到是线段树,考虑如何实现区间+lowbit操作,lowbit是一个数中最小的一位1,形式是2的n次方,我们对一个二进制进行+lowbit模拟不难发现,一个数在经过不超过log(n)次操作后,其二进制形式中就只剩下了一个1,在此之后进行的+lowbit操作就全变成了*2,所以我们考虑在使用线段树的时候对每个区间加一个pd判断,如果当前区间内的所有数都已经变成了只有一位1,在此之后对该区间进行操作1,就可以直接进行区间乘法,注意题目要求最后结果模上一个数,而一个数在变成只有1个1之前不能取模,因为这样会影响后续判断,单独对一个数进行+lowbit操作不能对整个区间操作,所以需要一直推到线段树最底层然后逐层返回状态,这样是很耗费时间的,所以我们要使每个数尽可能快的变为只有1个1的状态
ac代码:
#include<bits/stdc++.h>
#define endl '\n'
#define ll long long
#define INF 0x3f3f3f3f
#define pb push_back
#define int long long
#define max(a, b) (((a) > (b)) ? (a) : (b))
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define Mirai ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
using namespace std;
typedef pair<int,int> pii;
const int N=1e5+10,mod=998244353;
struct Node
{
int l,r;
int sum,lazy,pd;
}tr[N<<2];
//此处pd用来标记此区间的所有数是否已经只剩一位1
//如果只剩一位1即可直接用lazy进行区间乘法
int w[N];
int op,l,r,q,n;
int lowbit(int x)
{
return x&-x;
}
void change(int u,int lazy)
{
tr[u].sum=((tr[u].sum%mod)*(lazy%mod))%mod;
tr[u].lazy=((tr[u].lazy%mod)*(lazy%mod))%mod;
}
void pushup(int u)
{
tr[u].sum=((tr[u<<1].sum%mod)+(tr[u<<1|1].sum%mod)+mod)%mod;
tr[u].pd=tr[u<<1].pd&tr[u<<1|1].pd;//只有左右区间pd都为1,父区间pd才能为1
}
void pushdown(int u)
{
if(tr[u].lazy>1)
{
change(u<<1,tr[u].lazy);
change(u<<1|1,tr[u].lazy);
tr[u].lazy=1;
}
}
void build(int u,int l,int r)
{
if(l==r)
{
tr[u]={l,r,w[l],1,0};
if(w[l]==lowbit(w[l]))tr[u].pd=1;//建立线段树的时候注意预先判断pd条件
}
else
{
tr[u]={l,r};
tr[u].lazy=1;
int mid=l+r>>1;
build(u<<1,l,mid);
build(u<<1|1,mid+1,r);
pushup(u);
}
}
void modify(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r&&tr[u].pd==1)//如果区间pd==1则可以直接去加乘2
{
change(u,2);
return ;
}
if(tr[u].l==tr[u].r)//如果一直找到了最底层,则进行+lowbit操作然后逐层返回状态
{
tr[u].sum=tr[u].sum+lowbit(tr[u].sum);//注意此处不能%mod
if(tr[u].sum==lowbit(tr[u].sum))tr[u].pd=1;//操作结束后判断一次该数是否满足只有一位1的条件,然后更新状态
return ;
}
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
if(l<=mid)modify(u<<1,l,r);
if(r>mid)modify(u<<1|1,l,r);
pushup(u);
}
int query(int u,int l,int r)
{
if(tr[u].l>=l&&tr[u].r<=r)return tr[u].sum%mod;
pushdown(u);
int mid=tr[u].l+tr[u].r>>1;
int res=0;
if(l<=mid)res=(res%mod+query(u<<1,l,r)%mod)%mod;
if(r>mid)res=(res%mod+query(u<<1|1,l,r)%mod)%mod;
return res;
}
void solve()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>w[i];
build(1,1,n);
cin>>q;
while(q--)
{
cin>>op>>l>>r;
if(op==1)modify(1,l,r);
else cout<<query(1,l,r)<<endl;
}
}
signed main()
{
Mirai;
int T=1;
cin>>T;
while(T--)
{
solve();
}
}