2018.07.30 cogs2632. [HZOI 2016] 数列操作d(线段树)

传送门
线段树基本操作
区间加等差数列,维护区间和。
对于每个区间维护等差数列首项和公差,易证这两个东西都是可合并的,然后使用小学奥数的知识就可以切掉这题。
代码:

#include
#define lc (p<<1)
#define rc (p<<1|1)
#define mid (T[p].l+T[p].r>>1)
#define N 300005
#define mod 1000000007
#define ll long long
using namespace std;
inline ll read(){
    ll ans=0;
    char ch=getchar();
    while(!isdigit(ch))ch=getchar();
    while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
    return ans;
}
inline ll write(ll x){
    if(x>9)write(x/10);
    putchar((x%10)^48);
}
int n,m,LL,RR;
ll a[N];
struct Node{int l,r;ll sum,add,fir;}T[N<<2];
inline void pushup(int p){
    T[p].sum=T[lc].sum+T[rc].sum;
    if(T[p].sum>=mod)T[p].sum-=mod;
}
inline void pushadd(int p,ll fir,ll v){
    T[p].add+=v,T[p].fir+=fir;
    if(T[p].add>=mod)T[p].add-=mod;
    if(T[p].fir>=mod)T[p].fir-=mod;
    (T[p].sum+=(T[p].r-T[p].l+1)*(2*fir+(T[p].r-T[p].l)*v)/2)%=mod;
}
inline void pushdown(int p){
    if(!T[p].add)return;
    pushadd(lc,T[p].fir,T[p].add);
    pushadd(rc,T[p].fir+T[p].add*(mid-T[p].l+1),T[p].add);
    T[p].add=T[p].fir=0;
}
inline void build(int p,int l,int r){
    T[p].l=l,T[p].r=r,T[p].add=T[p].fir=T[p].sum=0;
    if(l==r)return;
    build(lc,l,mid),build(rc,mid+1,r);
}
inline void update(int p,int ql,int qr,ll v){
    if(ql>T[p].r||qr<T[p].l)return;
    if(ql<=T[p].l&&T[p].r<=qr)return pushadd(p,v*(T[p].l-LL),v);
    pushdown(p);
    if(qr<=mid)update(lc,ql,qr,v);
    else if(ql>mid)update(rc,ql,qr,v);
    else update(lc,ql,mid,v),update(rc,mid+1,qr,v);
    pushup(p);
}
inline ll query(int p,int ql,int qr){
    if(ql>T[p].r||qr<T[p].l)return 0;
    if(ql<=T[p].l&&T[p].r<=qr)return T[p].sum;
    pushdown(p);
    if(qr<=mid)return query(lc,ql,qr);
    if(ql>mid)return query(rc,ql,qr);
    ll ret=query(lc,ql,mid)+query(rc,mid+1,qr);
    if(ret>=mod)ret-=mod;
    return ret;
}
int main(){
    freopen("segment.in","r",stdin);
    freopen("segment.out","w",stdout);
    n=read(),m=read();
    build(1,1,n);
    while(m--){
        int op=read(),l=LL=read(),r=RR=read();
        if(op==1){ll v=read();update(1,l,r,v);}
        else printf("%lld\n",query(1,l,r));
    }
    return 0;
}

你可能感兴趣的:(#,线段树)