D - Lowbit

题目链接:SDUT 2023 summer team contest(for 22) - 5 - Virtual Judge (vjudge.net)

思路:因为一个数不断进行lowbit最后得到的数将会是lowbit之前的数,也就是相加后是之前一个数的二倍,可以优先处理这些数,最后二倍 的处理区间。

代码:

#include <bits/stdc++.h>
#define int long long
#define lowbit(x) ((x)&(-x))
#define dbug(x) cout<<#x<<'='<<x<<endl;
#define x first
#define y second
#define pb push_back
const int N = 1e5 + 5;
const int INF = 0x3f3f3f3f;
const int mod = 998244353;
using namespace std;
typedef pair<int, int>pii;
int n, m;
map<int, int>mp;
int a[N],b[N];
struct node{
    int l,r,lazy,sum,pd;//lazy为懒标记,pd为判断是否已经和lowbit后相等
}g[N<<2];
void pushup(int i){
    g[i].sum=(g[i<<1].sum+g[i<<1|1].sum)%mod;
    g[i].pd=min(g[i<<1].pd,g[i<<1|1].pd);//判断该区间中的所有数是否和lowbit一样

}
void pushdown(int i){
    if(g[i].lazy>1){
        g[i<<1].sum=(g[i<<1].sum*g[i].lazy)%mod,g[i<<1].lazy=(g[i].lazy*g[i<<1].lazy)%mod;//懒标记向下继承,求出子区间的sum
        g[i<<1|1].sum=(g[i<<1|1].sum*g[i].lazy)%mod,g[i<<1|1].lazy=(g[i].lazy*g[i<<1|1].lazy)%mod;
        g[i].lazy=1;
    }
}
void build(int i,int l,int r){
    if(l==r)g[i].l=l,g[i].r=r,g[i].sum=a[l],g[i].lazy=1,g[i].pd=0;
    else{
        g[i].l=l,g[i].r=r,g[i].lazy=1;
        int mid=l+r>>1;
        build(i<<1,l,mid),build(i<<1|1,mid+1,r);
        pushup(i);
    }
}
void modify(int i,int l,int r){
    if(g[i].l>=l&&g[i].r<=r&&g[i].pd==1){//如果pd为1代表里面的所有数都已经和lowbit一样
        g[i].sum=g[i].sum*2%mod;//因为一样所以是两倍
        g[i].lazy=g[i].lazy*2%mod;//懒标记也乘2
        return ;
    }
    if(g[i].l==g[i].r){//先不直接处理整个区间,而是先把和lowbit不同的数逐渐处理成相同
        g[i].sum=g[i].sum+lowbit(g[i].sum);
        if(g[i].sum==lowbit(g[i].sum))g[i].pd=1;//一旦相同则标记
        return ;
    }
    pushdown(i);
    int mid=g[i].l+g[i].r>>1;
    if(mid>=l)modify(i<<1,l,r);
    if(mid<r)modify(i<<1|1,l,r);
    pushup(i);
}
int query(int i,int l,int r){//区间求和板子
    if(g[i].l>=l&&g[i].r<=r)return g[i].sum%mod;
    pushdown(i);
    int mid=g[i].l+g[i].r>>1;
    int res=0;
    if(l<=mid)res=(res+query(i<<1,l,r))%mod;
    if(mid<r)res=(res+query(i<<1|1,l,r))%mod;
    return res;
}
void solve () {
    cin>>n;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    build(1,1,n);
    cin>>m; 
    while(m--){
        int op,l,r;

        cin>>op>>l>>r;
        if(op==1){
            modify(1,l,r);
        }
        else{
            cout<<query(1,l,r)%mod<<endl; 
        }
   
    }
    for(int i=1;i<=4*n;i++){
        g[i]={0,0,0,0,0};
    }
}
signed main () {
   int T = 1; 
   std::ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
        cin>>T;
   while (T --) solve ();
   return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值