【LOJ】#2512. 「BJOI2018」链上二次求和

题面

题解

转化一下可以变成所有小于等于r的减去小于等于l - 1的
然后我们求小于等于x的

显然是
\(\sum_{i = 1}^{n} \sum_{j = 1}^{min(i,x)} sum[i] - sum[i - j]\)
对于\([x,N - x]\)前缀和被加了\(x\)
对于\([1,N - x]\)前缀和被减了\(x\)
对于\([1,x - 1]\)前缀和被加了下标那么多遍
对于\([N - x + 1,N]\)前缀和被减了N - 下标遍

然后要维护什么就很清楚了
\(\sum_{i = L}^{R} sum[i]\)\(\sum_{i = L}^{R} sum[i] * i\)
区间加相当于给一段前缀和加上一个等差数列,这段区间之后加上一个常值数列

区间加等差数列维护区间和,第一个很好维护,第二个只要拆拆式子就好了
\(\sum_{i = 0}^{R - L + 1} (L + i) * (a + i * d)\)
\(\sum_{i = 0}^{R - L + 1} (L + i) * a + (L + i) * i * d\)
\(\sum_{i = 0}^{R - L + 1} (L + i) * a + L * i * d + i * i * d\)
拆成三段,第一段是一个等差数列乘一个常数
第二段是\(L\)乘上一个等差数列
第三个可以用公式\(\frac{k(k + 1)(2 * k + 1)}{6}\)算然后乘上\(d\)

啥,你说常数多大?我没细想= =

最慢好像跑了2.5s,时限4s。。。

代码

#include <bits/stdc++.h>
#define fi first
#define se second
#define pii pair<int,int>
#define space putchar(' ')
#define enter putchar('\n')
#define mp make_pair
#define MAXN 200005
#define pb push_back
//#define ivorysi
using namespace std;
typedef long long int64;
typedef unsigned int u32;
template<class T>
void read(T &res) {
    res = 0;char c = getchar();T f = 1;
    while(c < '0' || c > '9') {
    	if(c == '-') f = -1;
    	c = getchar();
    }
    while(c >= '0' && c <= '9') {
    	res = res * 10 + c - '0';
    	c = getchar();
    }
    res *= f;
}
template<class T>
void out(T x) {
    if(x < 0) {putchar('-');x = -x;}
    if(x >= 10) {
    	out(x / 10);
    }
    putchar('0' + x % 10);
}
const int MOD = 1000000007;
int inc(int a,int b) {
    return a + b >= MOD ? a + b - MOD : a + b;
}
int mul(int a,int b) {
    return 1LL * a * b % MOD;
}
void update(int &x,int y) {
    x = inc(x,y);
}
int a[MAXN],N,M;
struct node {
    int L,R,a,b,sum[2];
}tr[MAXN * 4];
int f(int x) {
    return mul(mul(x,(MOD + 1) / 6),mul(x + 1,(1LL * 2 * x + 1) % MOD));
}
void addlazy(int u,int a,int b) {
    int l = tr[u].R - tr[u].L;
    update(tr[u].sum[0] , mul( inc( mul( 2 , a ) , mul( b , l ) ) , mul( l + 1 , (MOD + 1) / 2 ) ) );
    update(tr[u].sum[1] , mul( a , mul( tr[u].R + tr[u].L , mul( l + 1 , (MOD + 1) / 2 ) ) ) );
    update(tr[u].sum[1] , mul( mul( tr[u].L , b ) , mul( mul( l , l + 1 ) , (MOD + 1) / 2 ) ) );
    update(tr[u].sum[1] , mul( b , f(l) ) );
    update(tr[u].a,a);update(tr[u].b,b);
}
void update(int u) {
    for(int i = 0 ; i <= 1 ; ++i) {
        tr[u].sum[i] = inc(tr[u << 1].sum[i],tr[u << 1 | 1].sum[i]);
    }
}
void push_down(int u) {
    if(tr[u].a || tr[u].b) {
        int mid = (tr[u].L + tr[u].R) >> 1;
        addlazy(u << 1,tr[u].a,tr[u].b);
        addlazy(u << 1 | 1,inc(tr[u].a,mul(mid + 1 - tr[u].L,tr[u].b)),tr[u].b);
        tr[u].a = tr[u].b = 0;
    }
}
void build(int u,int l,int r) {
    tr[u].L = l;tr[u].R = r;
    if(l == r) {tr[u].sum[0] = a[l];tr[u].sum[1] = mul(a[l],l);return;}
    int mid = (l + r) >> 1;
    build(u << 1,l,mid);build(u << 1 | 1,mid + 1,r);
    update(u);
}
int Query(int u,int l,int r,int id) {
    if(tr[u].L == l && tr[u].R == r) return tr[u].sum[id];
    int mid = (tr[u].L + tr[u].R) >> 1;
    push_down(u);
    if(r <= mid) return Query(u << 1,l,r,id);
    else if(l > mid) return Query(u << 1 | 1,l,r,id);
    else return inc(Query(u << 1,l,mid,id),Query(u << 1 | 1,mid + 1,r,id));
}
void Change(int u,int l,int r,int a,int b) {
    if(tr[u].L == l && tr[u].R == r) {addlazy(u,a,b);return;}
    push_down(u);
    int mid = (tr[u].L + tr[u].R) >> 1;
    if(r <= mid) Change(u << 1,l,r,a,b);
    else if(l > mid) Change(u << 1 | 1,l,r,a,b);
    else {Change(u << 1,l,mid,a,b);Change(u << 1 | 1,mid + 1,r,inc(a,mul(b,mid + 1 - l)),b);}
    update(u);
}
void Init() {
    read(N);read(M);
    for(int i = 1 ; i <= N ; ++i) {
        read(a[i]);
        update(a[i],a[i - 1]);
    }
    build(1,1,N);
}
int Calc(int x) {
    if(!x) return 0;
    int res = 0;
    update(res,mul(Query(1,x,N,0),x));
    if(N != x) update(res,MOD - mul(Query(1,1,N - x,0),x));
    if(x != 1) update(res,Query(1,1,x - 1,1));
    update(res,MOD - inc( mul( N , Query(1,N - x + 1,N,0) ) , MOD - Query(1,N - x + 1,N,1) ) );
    return res;
}
void Solve() {
    int op,l,r,d;
    for(int i = 1 ; i <= M ; ++i) {
        read(op);read(l);read(r);
        if(op == 1) {
            read(d);
            if(l > r) swap(l,r);
            Change(1,l,r,d,d);
            if(r < N) Change(1,r + 1,N,mul(d,r - l + 1),0);
        }
        else {
            out(inc(Calc(r),MOD - Calc(l - 1)));enter;
        }
    }
}
int main() {
#ifdef ivorysi
    freopen("f1.in","r",stdin);
#endif
    Init();
    Solve();
}
posted @ 2018-11-18 11:00  sigongzi  阅读(572)  评论(0编辑  收藏  举报