链上二次求和

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int MAXN = 202020;
const int MOD = 1000000007;
const int REV2 = (MOD + 1) / 2;
const int REV6 = (MOD + 1) / 6;
inline int get_polynomial_sum(int a0, int a1, int a2, int x)
{
    return (((long long)a2 * (2 * x + 1) % MOD * REV6 + (long long)a1 * REV2) % MOD * (x + 1) + a0) % MOD * x % MOD;
}
int n, m, a[MAXN];
class Segment_tree
{
public:
    int st, ed;
    Segment_tree *l, *r;
    int sum;
    int a[3];//lazy tags
    //a[0]: add 1, 1, 1, 1, ...
    //a[1]: add 1, 2, 3, 4, ...
    //a[2]: add 1, 4, 9, 16, ...
    Segment_tree(int st, int ed): st(st), ed(ed), l(0), r(0), sum(0)
    {
        a[0] = a[1] = a[2] = 0;
    }
    Segment_tree(int st, int ed, Segment_tree *l, Segment_tree *r): st(st), ed(ed), l(l), r(r)
    {
        a[0] = a[1] = a[2] = 0;
        update();
    }
    int len() const
    {
        return ed - st + 1;
    }
    void add(int b0, int b1, int b2)
    {
        a[0] = (a[0] + b0) % MOD;
        a[1] = (a[1] + b1) % MOD;
        a[2] = (a[2] + b2) % MOD;
        sum = (sum + get_polynomial_sum(b0, b1, b2, len())) % MOD;
    }
    void down()
    {
        if(!a[0] && !a[1] && !a[2])
            return;
        l->add(a[0], a[1], a[2]);
        int llen = l->len();
        r->add((((long long)a[2] * llen + a[1]) % MOD * llen + a[0]) % MOD, ((long long)a[2] * llen * 2 + a[1]) % MOD, a[2]);
        a[0] = a[1] = a[2] = 0;
    }
    void update()
    {
        sum = (l->sum + r->sum) % MOD;
    }
};
Segment_tree *root;
Segment_tree *build(int st, int ed)
{
    return st == ed ? new Segment_tree(st, ed) : new Segment_tree(st, ed, build(st, (st + ed) >> 1), build(((st + ed) >> 1) + 1, ed));
}
long long query(Segment_tree *p, int st, int ed)
{
    if(p->st >= st && p->ed <= ed)
        return p->sum;
    p->down();
    if(ed <= p->l->ed)
        return query(p->l, st, ed);
    if(st >= p->r->st)
        return query(p->r, st, ed);
    return query(p->l, st, ed) + query(p->r, st, ed);
}
void add(Segment_tree *p, int st, int ed, int b0, int b1, int b2)
{
//    if(p == root)
//        printf("add: [%d, %d] %d + %dx + %dx^2\n", st, ed, b0, b1, b2);
    if(p->st >= st && p->ed <= ed)
    {
        p->add(b0, b1, b2);
        return;
    }
    p->down();
    if(ed <= p->l->ed)
        add(p->l, st, ed, b0, b1, b2);
    else if(st >= p->r->st)
        add(p->r, st, ed, b0, b1, b2);
    else
    {
        add(p->l, st, p->l->ed, b0, b1, b2);
        int llen = p->l->ed - st + 1;
        add(p->r, p->r->st, ed, (((long long)b2 * llen + b1) % MOD * llen + b0) % MOD, ((long long)b2 * llen * 2 + b1) % MOD, b2);
    }
    p->update();
}
void change(int u, int v, int d)
{
    if(u > v)
        swap(u, v);
    int len = v - u + 1;
    v = n - v + 1;
    add(root, 1, n, 0, (long long)len * d % MOD, 0);
    if(u + 1 <= n)
        add(root, u + 1, n, 0, (long long)(MOD - d) * REV2 % MOD, (long long)(MOD - d) * REV2 % MOD);
    if(u + len + 1 <= n)
        add(root, u + len + 1, n, 0, (long long)d * REV2 % MOD, (long long)d * REV2 % MOD);
    if(v + 1 <= n)
        add(root, v + 1, n, 0, (long long)(MOD - d) * REV2 % MOD, (long long)(MOD - d) * REV2 % MOD);
    if(v + len + 1 <= n)
        add(root, v + len + 1, n, 0, (long long)d * REV2 % MOD, (long long)d * REV2 % MOD);
}
int main()
{
//    freopen("sum.in", "r", stdin);
//    freopen("sum.out", "w", stdout);
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i++)
        scanf("%d", &a[i]);
    root = build(1, n);
    for(int i = 1; i <= n; i++)
        if(a[i])
            change(i, i, a[i]);
    for(int i = 1; i <= m; i++)
    {
        int tp, u, v, d;
        scanf("%d%d%d", &tp, &u, &v);
        if(tp == 1)
        {
            scanf("%d", &d);
            change(u, v, d);
        }
        else
        {
            printf("%d\n", (int)(query(root, u, v) % MOD));
        }
    }
    return 0;
}

 

posted @ 2018-04-28 11:35  探险家Mr.H  阅读(288)  评论(0编辑  收藏  举报