2020牛客寒假算法基础集训营3 G题

本文介绍了一种使用树状数组解决复杂前缀和问题的方法,通过具体的代码实现,展示了如何进行单点修改和前缀和查询,适用于处理大量更新和查询操作的场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

牛牛的Link Power II

树状数组做比较简单,只要维护前缀和就行;

#include<bits/stdc++.h>
#define ll long long
#define pa pair<int,int>
#define lson k<<1
#define rson k<<1|1
//ios::sync_with_stdio(false);
using namespace std;
const int N=500100;
const int M=200100;
const ll mod=1e9+7;
int n,m,tr1[N],tr2[N];
vector<int>ve;
int b[N];
ll ans;
int lowbit(int k){
    return k & (-k);
}
void add1(int p,int q){//p点加上q,单点修改
    while(p<=n){
        tr1[p]+=q;
        tr1[p]%=mod;
        p+=lowbit(p);
    }
}
ll sum1(int p){//单点查询,就是求前缀和
    ll s=0;
    while(p!=0){
        s+=(ll)tr1[p];
        s%=mod;
        p-=lowbit(p);
    }
    return s;
}
void add2(int p,int q){//p点加上q,单点修改
    while(p<=n){
        tr2[p]+=q;
        tr2[p]%=mod;
        p+=lowbit(p);
    }
}
ll sum2(int p){//单点查询,就是求前缀和
    ll s=0;
    while(p!=0){
        s+=(ll)tr2[p];
        s%=mod;
        p-=lowbit(p);
    }
    return s;
}
int main(){
    ios::sync_with_stdio(false);
    cin>>n;
    string s;
    cin>>s;
    cin>>m;
    for(int i=0;i<n;i++){
        if(s[i]=='1') {
        	add1(i+1,i+1);
			add2(i+1,1);
			ve.push_back(i+1);
		}
    }
    if(ve.size()==1||ve.size()==0) cout<<0<<endl;
    else if(ve.size()==2){
        ans=ve[1]-ve[0];
        cout<<ve[1]-ve[0]<<endl;
    }
    else{
        ll sum=ve[1]-ve[0];
        sum%=mod;
        ans=sum;
        for(int i=2;i<ve.size();i++){
            sum+=(ll)(ve[i]-ve[i-1])*(ll)(i);
            sum%=mod;
            ans+=sum;
            ans%=mod;
        } 
        cout<<ans<<endl;
    }
    for(int i=1;i<=m;i++){
        int q,p;
        cin>>q>>p;
        if(q==1){
            ll t1=(ll)p*(sum2(p-1)-sum2(0))%mod-(sum1(p-1)-sum1(0));
            ll t2=(sum1(n)-sum1(p))-(ll)p*(sum2(n)-sum2(p))%mod;
            ans=((ans+t1+t2)%mod+mod)%mod;
            cout<<ans<<endl;
            add1(p,p);
            add2(p,1);
        }
        else{
            ll t1=(ll)p*(sum2(p-1)-sum2(0))%mod-(sum1(p-1)-sum1(0));
            ll t2=(sum1(n)-sum1(p))-(ll)p*(sum2(n)-sum2(p))%mod;
            ans=((ans-t1-t2)%mod+mod)%mod;
            cout<<ans<<endl;
            add1(p,-p);
            add2(p,-1);
        }
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值