ACM-ICPC 2018 徐州赛区网络预赛 H. Ryuji doesn't want to study [ 线段树 ]

题目链接:

ACM-ICPC 2018 徐州赛区网络预赛 H. Ryuji doesn't want to study

题意概括:

对于一个序列,查询操作是给出一个区间[l, r],求

\sum _{i=1}^{r-l+1}i*a[r-i+1]

还有单点修改序列的操作

数据范围:

n,q\leq 100000

a[i]\leq 1e9

题解分析:

频繁的区间询问、区间修改,很明显就是线段树的题了

对每个节点,维护三个变量

  • sum : 存储该序列区间所有值的和
  • ans : 存储该序列区间符合题意的询问值
  • cnt : 存储该序列区间中数的个数

则当向上更新,两个区间合并时的方法应该是

    tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
    tree[p].cnt = tree[p << 1].cnt + tree[p << 1 | 1].cnt;
    tree[p].ans = tree[p << 1].ans + tree[p << 1 | 1].ans + tree[p << 1].sum * tree[p << 1 | 1].cnt;

AC代码:

#include <stdio.h>
using namespace std;
const int MAXN=1e5 + 10;
typedef long long ll;
int origin[MAXN];

struct node {
    ll sum;
    ll ans;
    int cnt;
} tree[MAXN<<2];

void pushup(int p) {
    tree[p].sum = tree[p << 1].sum + tree[p << 1 | 1].sum;
    tree[p].cnt = tree[p << 1].cnt + tree[p << 1 | 1].cnt;
    tree[p].ans = tree[p << 1].ans + tree[p << 1 | 1].ans + tree[p << 1].sum * tree[p << 1 | 1].cnt;
}

void build(int p, int l, int r) {
    if (l == r) {
        tree[p].cnt = 1;
        tree[p].sum = origin[l];
        tree[p].ans = origin[l];
        return;
    }
    int mid = (l + r) >> 1;
    build(p << 1, l, mid);
    build(p << 1 | 1, mid + 1, r);
    pushup(p);
}

void update_node(int p, int l,int r, int q,int v) {
    if (l == r) {   //查询到点
        tree[p].sum = v;
        tree[p].ans = v;
        return;
    }
    int mid = (l + r) >> 1;
    if (q > mid) update_node(p << 1 | 1, mid + 1, r, q, v);
    else update_node(p << 1, l, mid, q, v);
    pushup(p);
}

node query(int p, int l, int r, int ql, int qr) {
    if (ql <= l && r <= qr)  return tree[p];    //被包含在询问区域内的区间(有效的部分)
    int mid = (l + r) >> 1;
    node temp, tempr, templ;
    tempr.cnt = tempr.sum = tempr.ans = 0;
    templ.cnt = templ.sum = templ.ans = 0;
    if (qr > mid) tempr = query(p << 1 | 1, mid + 1, r, ql, qr);
    //分块切割出有效的部分(已忽略无效部分)
    if (ql <= mid) templ = query(p << 1, l, mid, ql, qr);

    temp.cnt = templ.cnt + tempr.cnt;
    temp.sum = templ.sum + tempr.sum;
    temp.ans = templ.ans + tempr.ans + templ.sum * tempr.cnt;

    return temp;
}


int main () {
    int n, q;
    scanf("%d%d", &n, &q);
    for (int i = 1; i <= n; i++)
        scanf("%d", origin + i);
    build(1, 1, n);
    while(q--) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        if (a == 1) {
            printf("%lld\n", query(1, 1, n, b, c).ans);
        }
        else {
            update_node(1, 1, n, b, c);
        }
    }
}

 

                                              Ryuji doesn't want to study

Ryuji is not a good student, and he doesn't want to study. But there are n books he should learn, each book has its knowledge a[i].

Unfortunately, the longer he learns, the fewer he gets.
That means, if he reads books from l to r, he will get a[l] × L + a[l + 1] × (L − 1) + ⋯+ a[r − 1] × 2 + a[r] (L is the length of [ l, r ] that equals to r − l + 1). Now Ryuji has q questions, you should answer him:

1. If the question type is 1, you should answer how much knowledge he will get after he reads books [ l, r ].

2. If the question type is 2, Ryuji will change the ith book's knowledge to a new value.

Input

First line contains two integers n and q (n, q ≤ 100000). The next line contains n integers represent a[i](a[i] ≤ 1e9) .

Then in next q line each line contains three integers a, b, c, if a = 1, it means question type is1, and b, c represents [ l , r ].

if a = 2 , it means question type is 2 , and b, c means Ryuji changes the bth book' knowledge to c

Output

For each question, output one line with one integer represent the answer.

样例输入

5 3
1 2 3 4 5
1 1 3
2 5 0
1 4 5

样例输出

10
8

题目来源

ACM-ICPC 2018 徐州赛区网络预赛

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章