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 徐州賽區網絡預賽

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