筱玛爱线段树 (树状数组)

https://ac.nowcoder.com/acm/contest/946/

对操作顺序执行的话,会出现递归调用的情况,这样的话复杂度起码是m^2了,所以考虑把操作离线,然后逆序执行,这样的话已经执行过的就不会再执行了,然后利用数状数组维护每个操作执行的总次数的差分数组,这样的话每执行到一个操作的时候后面的操作调用该操作的次数就可以求出来了,相当于是把每个操作的总次数先算出来,然后再执行。

千万要注意: (A-B)%MOD这样写不行,因为会有负数情况,要+个MOD再% ,  (A-B+MOD)%MOD,对所有有%的数都要这样处理。

#include<bits/stdc++.h>
using namespace std;
#define ls rt<<1
#define rs (rt<<1)+1
#define ll long long
#define fuck(x) cout<<#x<<"     "<<x<<endl;
typedef pair<int,int> pii;
const int maxn=1e5+10;
const int mod=1e9+7;
int d[4][2]={1,0,-1,0,0,1,0,-1};
ll c[maxn],bit[maxn];
int n,m;;
struct node
{
    int opt,l,r;
}op[maxn];
int lowbit(int x){return x&-x;}
ll query(int x)
{
    ll ans=0;
    while(x>=1)
        ans+=bit[x],ans%=mod,x-=lowbit(x);
    return ans;
}
void add(int x,ll v)
{
    while(x<=m)
        bit[x]=(bit[x]+v+mod)%mod,x+=lowbit(x);
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=1;i<=m;i++) scanf("%d%d%d",&op[i].opt,&op[i].l,&op[i].r);
    for(int i=m;i>=1;i--)
    {
        ll tmp=(1LL+query(i))%mod;
        if(op[i].opt==1)
            c[op[i].l]=(c[op[i].l]+tmp)%mod,c[op[i].r+1]=(c[op[i].r+1]-tmp+mod)%mod;
        else
            add(op[i].l,tmp),add(op[i].r+1,-tmp);
    }
    for(int i=1;i<=n;i++){
        c[i]=(c[i]%mod+c[i-1]%mod)%mod;
        printf("%lld ",c[i]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/eason9906/p/11754736.html