bzoj 3155 Preprefix sum

来源:互联网 发布:开关电源设计仿真软件 编辑:程序博客网 时间:2024/06/07 04:48

3155: Preprefix sum
Time Limit: 1 Sec Memory Limit: 512 MB
Submit: 1208 Solved: 553
[Submit][Status][Discuss]
Description
这里写图片描述

Input

第一行给出两个整数N,M。分别表示序列长度和操作个数

接下来一行有N个数,即给定的序列a1,a2,….an

接下来M行,每行对应一个操作,格式见题目描述

Output

对于每个询问操作,输出一行,表示所询问的SSi的值。

Sample Input

5 3

1 2 3 4 5

Query 5

Modify 3 2

Query 5

Sample Output

35

32

HINT

1<=N,M<=100000,且在任意时刻0<=Ai<=100000


【分析】
大半夜水一道树状数组感觉还是很好哒…
我们只需要维护两个树状数组,一个cp[i],维护前缀和,另一个是cpp[i],维护sigema (n-i+1)*a[i]。到时候加加减减乱搞一下就好了。
算了…举个例子吧
比如 1 2 3 4 5 ,我们要求ans[3]
我们维护了 cp[3]=1+2+3
还维护了 cpp[3]=5*1+4*2+3*3
那么答案就是 cpp[3]-2*cp[3],很好理解吧。(2就是5-3得到的嘛)


【代码】

//bzoj 3155  Preprefix sum#include<iostream>#include<cstdio>#include<cmath>#include<cstring>#include<algorithm>#define ll long long#define M(a) memset(a,0,sizeof a)#define fo(i,j,k) for(i=j;i<=k;i++)using namespace std;const int mxn=100006;ll n,m;char ch[10];ll a[mxn],cp[mxn],cpp[mxn];inline ll lowbit(ll x) {return x&(-x);}inline void add(ll x,ll v){    ll tmp=(n-x+1)*v;    for(ll i=x;i<=n;i+=lowbit(i))      cp[i]+=v,cpp[i]+=tmp;}inline ll gets(ll x){    ll sum=0,ot=0;    for(ll i=x;i;i-=lowbit(i))      sum+=cpp[i],ot+=cp[i];    sum-=ot*(n-x);    return sum;}int main(){    ll i,j,x,y;    scanf("%lld%lld",&n,&m);    fo(i,1,n)    {        scanf("%lld",&a[i]);        add(i,a[i]);    }    while(m--)    {        scanf("%s",ch);        if(ch[0]=='Q')        {            scanf("%lld",&x);            printf("%lld\n",gets(x));        }        else        {            scanf("%lld%lld",&x,&y);            add(x,y-a[x]);            a[x]=y;        }    }    return 0;}
1 0
原创粉丝点击