Ryuji doesn‘t want to study 计蒜客 41186 线段树

Ryuji doesn’t want to study - 计蒜客 41186 - Virtual Judge (vjudge.net)

题意

给定一个数组 a [ N ] a[N] a[N],有两种操作

  • 给定 l , r l, r l,r, 查询 a [ l ] × L + a [ l + 1 ] × ( L − 1 ) + ⋯ + a [ r − 1 ] × 2 + a [ r ] a[l] \times L+a[l+1] \times(L-1)+\cdots+a[r-1] \times 2+a[r] a[l]×L+a[l+1]×(L1)++a[r1]×2+a[r] 的值
  • 给定 x , y x, y x,y, 使 a [ x ] = y a[x]=y a[x]=y

N N N 个数据, M M M 种操作,对于每个操作 1 1 1 输出计算结果。

分析

把题目给出的求和式变形,得到
∑ i = l r a i × ( r − i + 1 ) = ∑ i = l r a i × [ ( r + 1 ) − i ] = ( r + 1 ) ∑ i = l r a i − ∑ i = l n a i × i \begin{gathered} \sum_{i=l}^{r} a_{i} \times(r-i+1) \\ =\sum_{i=l}^{r} a_{i} \times[(r+1)-i] \\ =(r+1) \sum_{i=l}^{r} a_{i}-\sum_{i=l}^{n} a_{i} \times i \end{gathered} i=lrai×(ri+1)=i=lrai×[(r+1)i]=(r+1)i=lraii=lnai×i
于是我们可以通过维护两个线段树来求解

Code

#include <bits/stdc++.h>

using namespace std;
#define LL long long
#define ULL unsigned long long
#define PII pair<int,int>
#define PLL pair<LL,LL>
#define PUU pair<ULL,ULL>

#define debug(a) cout << #a << " " << a << endl
#define fi first
#define se second
#define pb push_back
#define db double

const int maxn = 1500;
const int N = 1e6 + 7, M = N * 2;
const int inf = 0x3f3f3f3f;
const LL INF = 0xFFFFFFFFFF; //图接近 INT_MAX 时的初始化 判断时使用大于等于
const long long mod = 1e9 + 7;

inline long long read();

struct Node {
    int l, r;
    LL v; // 区间[l,r]中的最大值
} tr[N * 4], tr2[N * 4];

void pushup2(int u) { //由子节点的信息,算父节点的信息
    tr2[u].v = tr2[u << 1].v + tr2[u << 1 | 1].v;
}

void build2(int u, int l, int r) {
    tr2[u] = {l, r};
    if (l == r) return;
    int mid = (l + r) >> 1;
    build2(u << 1, l, mid), build2(u << 1 | 1, mid + 1, r);
}

LL query2(int u, int l, int r) {
    if (tr2[u].l >= l && tr2[u].r <= r) return tr2[u].v; //树中结点,已经完全被包含在[l,r]中

    int mid = (tr2[u].l + tr2[u].r) >> 1;
    LL ans = 0;
    if (l <= mid) ans = query2(u << 1, l, r);
    if (r > mid) ans = ans + query2(u << 1 | 1, l, r);

    return ans;
}

void modify2(int u, int x, LL v) {
    if (tr2[u].l == tr2[u].r) tr2[u].v = v;
    else {
        int mid = (tr2[u].l + tr2[u].r) >> 1;
        if (x <= mid) modify2(u << 1, x, v);
        else modify2(u << 1 | 1, x, v);
        pushup2(u);
    }
}

void pushup(int u) { //由子节点的信息,算父节点的信息
    tr[u].v = tr[u << 1].v + tr[u << 1 | 1].v;
}

void build(int u, int l, int r) {
    tr[u] = {l, r};
    if (l == r) return;
    int mid = (l + r) >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}

LL query(int u, int l, int r) {
    if (tr[u].l >= l && tr[u].r <= r) return tr[u].v; //树中结点,已经完全被包含在[l,r]中

    int mid = (tr[u].l + tr[u].r) >> 1;
    LL ans = 0;
    if (l <= mid) ans = query(u << 1, l, r);
    if (r > mid) ans = ans + query(u << 1 | 1, l, r);

    return ans;
}

void modify(int u, int x, LL v) {
    if (tr[u].l == tr[u].r) tr[u].v = v;
    else {
        int mid = (tr[u].l + tr[u].r) >> 1;
        if (x <= mid) modify(u << 1, x, v);
        else modify(u << 1 | 1, x, v);
        pushup(u);
    }
}


int n, q;

int main() {

//	freopen("input.txt", "r", stdin);
//	freopen("output.txt", "w", stdout);

//	ios::sync_with_stdio(false);
    scanf("%d%d", &n, &q);
    build(1, 1, n);
    build2(1, 1, n);

    for (int i = 1; i <= n; i++) {
        LL x;
        scanf("%lld", &x);
        modify(1, i, x);
        modify2(1, i, x * (LL)i);
    }

    for (int cas = 1; cas <= q; cas++) {
        LL op, x, y;
        scanf("%lld%lld%lld", &op, &x, &y);
        if (op == 1) {
//            debug((y + 1) * query(1, x, y));
//            debug(query2(1, x, y));
            LL ans = (y + 1) * query(1, x, y) - query2(1, x, y);
            printf("%lld\n", ans);
        }
        else {
            LL chmod = x * y;
            modify(1, x, y);
            modify2(1, x, chmod);
        }
    }

    return 0;
}

inline LL read() {
    char ch = getchar();
    LL p = 1, data = 0;
    while (ch < '0' || ch > '9') {
        if (ch == '-')p = -1;
        ch = getchar();
    }
    while (ch >= '0' && ch <= '9') {
        data = data * 10 + (ch ^ 48);
        ch = getchar();
    }
    return p * data;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值