计蒜客 31460 - Ryuji doesn't want to study - [线段树][2018ICPC徐州网络预赛H题]

题目链接:https://nanti.jisuanke.com/t/31460

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 ll to rr, he will get $a[l] \times L + a[l+1] \times (L-1) + \cdots + a[r-1] \times 2 + a[r]$ ($L$ is the length of [ $l$, $r$ ] that equals to $r - l + 1$).

Now Ryuji has qq 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 \le 100000$).

The next line contains n integers represent $a[i]$($a[i] \le 1e9$).

Then in next qq line each line contains three integers $a,b,c$, if $a = 1$, it means question type is $1$, 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

题意:

给出 $n$ 本书编号 $1$ 到 $n$,每本书权值为 $w[i]$,给出 $q$ 个操作,

操作 $1$,给出区间 $[l,r]$,则区间长度为 $L = r - l + 1$,查询的答案应为 $a[l] \times L + a[l+1] \times (L-1) + \cdots + a[r-1] \times 2 + a[r]$,

操作 $2$,把在编号为 $b$ 的书的权值改成 $c$。

题解:

线段树维护两个和:

一个是普通的区间和 $\sum\limits_{i = l}^r {w[i]} = w[l] + \cdots + w[r]$;

另一个是 $\sum\limits_{i = l}^r {\left[ {w[i] \times \left( {n - i + 1} \right)} \right]} = w[l] \times \left( {n - l + 1} \right) + \cdots + w[r] \times \left( {n - r + 1} \right)$。

那么,对于所有的查询:

$\begin{array}{l}
Q\left( {l,r} \right) \\
= w\left[ l \right] \times \left( {r - l + 1} \right) + w\left[ {l + 1} \right] \times \left( {r - l} \right) + \cdots + w\left[ r \right] \times 1 \\
= \sum\limits_{i = l}^r {\left[ {w\left[ i \right] \times \left( {r - i + 1} \right)} \right]} \\
= \sum\limits_{i = l}^r {\left[ {w\left[ i \right] \times \left( {n - i + 1 - n + r} \right)} \right]} \\
{\rm{ = }}\sum\limits_{i = l}^r {\left[ {w\left[ i \right] \times \left( {n - i + 1} \right) - w\left[ i \right] \times \left( {n - r} \right)} \right]} \\
= \sum\limits_{i = l}^r {\left[ {w\left[ i \right] \times \left( {n - i + 1} \right)} \right]} - \left( {n - r} \right)\sum\limits_{i = l}^r {w\left[ i \right]} \\
\end{array}$

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;

int n,q;
ll a[maxn];

/********************************* Segment Tree - st *********************************/
struct Node{
    int l,r;
    ll val,sum;
}node[4*maxn];
void pushup(int root)
{
    node[root].val=node[root*2].val+node[root*2+1].val;
    node[root].sum=node[root*2].sum+node[root*2+1].sum;
}
void build(int root,int l,int r)
{
    if(l>r) return;
    node[root].l=l; node[root].r=r;
    node[root].val=0; node[root].sum=0;
    if(l==r)
    {
        node[root].val=a[l];
        node[root].sum=a[l]*(n-l+1);
    }
    else
    {
        int mid=l+(r-l)/2;
        build(root*2,l,mid);
        build(root*2+1,mid+1,r);
        pushup(root);
    }
}
void update(int root,int pos,ll val)
{
    if(node[root].l==node[root].r)
    {
        node[root].val=val;
        node[root].sum=val*(n-pos+1);
        return;
    }
    int mid=node[root].l+(node[root].r-node[root].l)/2;
    if(pos<=mid) update(root*2,pos,val);
    if(pos>mid) update(root*2+1,pos,val);
    pushup(root);
}
ll askval(int root,int st,int ed)
{
    if(st>node[root].r || ed<node[root].l) return 0;
    if(st<=node[root].l && node[root].r<=ed) return node[root].val;
    else return askval(root*2,st,ed)+askval(root*2+1,st,ed);
}
ll asksum(int root,int st,int ed)
{
    if(st>node[root].r || ed<node[root].l) return 0;
    if(st<=node[root].l && node[root].r<=ed) return node[root].sum;
    else return asksum(root*2,st,ed)+asksum(root*2+1,st,ed);
}
/********************************* Segment Tree - ed *********************************/

int main()
{
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<=q;i++)
    {
        int type;
        scanf("%d",&type);
        if(type==1)
        {
            int a,b;
            scanf("%d%d",&a,&b);
            ll A=asksum(1,a,b);
            ll B=askval(1,a,b);
            //cout<<A<<" "<<B<<endl;
            printf("%lld\n",A-(n-b)*B);
        }
        else
        {
            int a; ll b;
            scanf("%d%lld",&a,&b);
            update(1,a,b);
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/dilthey/p/9619434.html