[COGS2632] [HZOI 2016] 数列操作d

来源:互联网 发布:梦想网络 编辑:程序博客网 时间:2024/04/28 20:24

题目

一个长度为n的序列,一开始序列数的权值都是0,有m次操作
支持两种操作,
1 L R x,给区间[L,R]内位置为pos的数加上(posL)x
0 L R,查询区间[L,R]内的权值和
最终答案对1e9+7取模

题解

这是我偶然翻到学弟学妹们出的一道题,于是就做了做。
首先这道题肯定能用线段树做,随便打打标记。
但是这道题也可以用树状数组做,更快,但是思想应该比线段树复杂些,就当是锻炼一下了。
下面是树状数组做法。

便于理解,将题目中的xk表示。
树状数组求区间[L,R]权值和的一般做法就是Sum(R)Sum(L1)。于是,首要任务就是找到正确的单点插入方法,使得可以利用树状数组求出Sum(x)

首先考虑只有一次插入[L1,R1] k1,那么Sum(x)如何求得呢?注意到,每次插入都很有规律,相当于一条线段,所以可以容易求出这个插入区间的一个区间段上的区间和。

  • L1xR1时,
    Sum(x)=i=1L110+i=L1x(iL1)k1=(xL1)(xL1+1)k1/2

    K=k/2
    Sum(x)=(xL1)(xL1+1)K1=x2(K1)+x(12L1)K1+(L21L1)K1

    注意到K1,(12L1)K1,(L21L1)K1都与x无关,对[L1,R1]中每个Sum(x)都不变,于是可以单点插入这三种值,记他们为A1,B1,C1,分别插入到树状数组A,B,C中,分别代表二次项系数、一次项系数和常数项,则Sum(x)=A1x2+B1x+C1
  • x>R1时,这条线段不存在了,那么在R1+1处插入A1,B1,C1,但这条线段对Sum(x)有贡献,需要将他的贡献K1(R1L1)(R1L1+1)插入到常数项的R1+1位置。

现在考虑多条线段的情形,容易发现可以线性叠加,求出2的逆元,优化一下代码,这道题就做完了。

代码

/// by ztx/// blog.csdn.net/hzoi_ztx#include <bits/stdc++.h>#define Rep(i,l,r) for(i=(l);i<=(r);i++)#define rep(i,l,r) for(i=(l);i< (r);i++)#define Rev(i,r,l) for(i=(r);i>=(l);i--)#define rev(i,r,l) for(i=(r);i> (l);i--)#define Each(i,v)  for(i=v.begin();i!=v.end();i++)#define r(x)   read(x)typedef long long ll ;typedef double lf ;int CH , NEG ;template <typename TP>inline void read(TP& ret) {    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;    if (CH == '-') NEG = true , CH = getchar() ;    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;    if (NEG) ret = -ret ;}#define  kN   300010LL#define  mod  1000000007LL#define  half 500000004LL#define  lb   (p&(-p))int n, A[kN], B[kN], C[kN];inline void Delta(int p,int w,int c[kN]) {    for (;p<=n;p+=lb) (c[p] += w) %= mod;}inline int Sum(int p,int c[kN]) {    int ret = 0;    for (;p;p-=lb) (ret += c[p]) %= mod;    return ret;}inline int Sum(int p) {    return (1LL*Sum(p,A)*p%mod*p%mod+1LL*Sum(p,B)*p%mod+1LL*Sum(p,C)%mod)%mod;}inline void Modify(int L,int R,ll x) {    x = x*half%mod;    Delta(L,x,A);    Delta(L,x*(1LL-2*L)%mod,B);    Delta(L,x*L%mod*(L-1)%mod,C);    Delta(R+1,-x,A);    Delta(R+1,-x*(1LL-2*L)%mod,B);    Delta(R+1,(-x*L%mod*(L-1)%mod + x*(R-L)%mod*(R-L+1)%mod)%mod,C);}inline void Query(int L,int R) {    printf("%lld\n", ((1LL*Sum(R)-Sum(L-1))%mod+mod)%mod);}int main() {    freopen("segment.in","r",stdin);    freopen("segment.out","w",stdout);    int m, L, R, x;    r(n), r(m);    while (m --> 0) {        r(L);        if (L)            r(L), r(R), r(x),            Modify(L,R,x);        else            r(L), r(R),            Query(L,R);    }    END: getchar(), getchar();    return 0;}
原创粉丝点击