[树状数组]code[vs] 1082——线段树练习 3

来源:互联网 发布:手机淘宝的物流在哪看 编辑:程序博客网 时间:2024/05/22 00:31

ps:博主又A这种水题显然是为了水blog有新姿势。

题目梗概

区间加,询问区间和。

解题思路

什么垃圾,直接线段树。
树状数组也可以区间加的啊,代码短小,常数小。
当然与普通树状数组有所不同。
a[i]=w[i]w[i1],这样修改区间[L,R]显然只需要修改a[L],a[R+1][1,x]的和显然就是

i=11a[i]+i=21a[i]+...+i=1xa[i]

稍微化一下就是
ni=1xa[i](0a[1]+1a[2]+...+(x1)a[x])

那么我们在维护a[i]的同时也维护一个b[i]=(i1)a[i]
区间和容斥一下就可以了。

#include<cstdio>#define LL long longusing namespace std;const int maxn=200005;int n,Q;LL a[maxn],b[maxn];inline int _read(){    int num=0;char ch=getchar();    while (ch<'0'||ch>'9') ch=getchar();    while (ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();    return num;}int lowbit(int x){return x&(-x);}void change(int x,int y){for (int i=x;i<=n;i+=lowbit(i)) a[i]+=y,b[i]+=(LL)(x-1)*y;}LL ask(int x){LL num=0;for (int i=x;i;i-=lowbit(i)) num+=(LL)x*a[i]-b[i];return num;}int main(){    freopen("exam.in","r",stdin);    freopen("exam.out","w",stdout);    n=_read();    for (int i=1;i<=n;i++){        int x=_read();        change(i,x);change(i+1,-x);    }    Q=_read();    while(Q--){        int d=_read(),L=_read(),R=_read(),x;        if (d==1){            x=_read();            change(L,x);change(R+1,-x);        }else printf("%lld\n",ask(R)-ask(L-1));    }    return 0;}
阅读全文
1 0
原创粉丝点击