• 【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('
    ')
    #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();
    }
    
  • 相关阅读:
    java多态课后作业
    java继承与接口课后作业
    java数组课后作业
    javaString课后作业
    Java类与对象课后作业
    java方法课后作业
    java基本知识课后作业
    读《大道至简》第二章有感
    课堂作业(字符串转化并计算)
    读《大道至简》第一章有感
  • 原文地址:https://www.cnblogs.com/ivorysi/p/9977244.html
Copyright © 2020-2023  润新知