poj 3468 A Simple Problem with Integers(线段树+树状数组区间更新区间查询)

来源:互联网 发布:百度网盘mac版怎么安装 编辑:程序博客网 时间:2024/04/29 12:05

A Simple Problem with Integers

Time Limit: 5000MS Memory Limit: 131072K
Total Submissions: 122283 Accepted: 37929
Case Time Limit: 2000MS
Description

You have N integers, A1, A2, … , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1, A2, … , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
“C a b c” means adding c to each of Aa, Aa+1, … , Ab. -10000 ≤ c ≤ 10000.
“Q a b” means querying the sum of Aa, Aa+1, … , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input10 51 2 3 4 5 6 7 8 9 10Q 4 4Q 1 10Q 2 4C 3 6 3Q 2 4Sample Output455915HintThe sums may exceed the range of 32-bit integers.

树状数组

分析:
首先不考虑原始的情况,我们只考虑区间更新过后带来的影响的话,首先对于询问一个区间当中的元素和的话,肯定就是这个区间的原始的元素和,加上区间更新后所带来的影响,所以我们用a[]数组来保存前i个元素的和。

然后考虑区间更新所带来的影响,采用差分的思想,
设原数组第i位的值为ai,di=ai−a[i−1],则有(这里认为a0=0,此时的a表示的是数组中的原始值,与代码中的a不一样):

这里写图片描述
所以有:
这里写图片描述

这里写图片描述

于是我们把原数组差分后维护两个树状数组,一个维护di,一个维护di×i。
这样区间求和时可以在两个树状数组中查询得到前缀和,区间修改时就是差分数组的修改,每次修改两个点即可。
其中c[i]维护的是d[i],c1[i]维护的是d[i]×i。

但是这里的c[]和c1[]都是差分数组,保存的也就只是更新所带来的值的变化,但因为这里要求的是在原来的基础上更新后的区间和,所以最终还要加上最原始的区间和。

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;long long int a[510000],c[510000],cc[510000];int n,m;int lowbit(int x){    return x&(-x);}void update(long long int x,long long int v){    for(long long int i=x;i<=n;i+=lowbit(i))    {        c[i]+=v;        cc[i]+=(long long )x*v;    }}long long int sum(long long int x){    long long int ans=0;    for(int i=x;i;i-=lowbit(i))        ans+=(x+1)*c[i]-cc[i];    return ans+a[x];}int main(){    char ch;    long long int s,r,va,num;    while(scanf("%d%d",&n,&m)!=EOF)    {        memset(a,0,sizeof(a));        memset(c,0,sizeof(c));        memset(cc,0,sizeof(cc));        for(int i=1;i<=n;i++)        {            scanf("%lld",&num);            a[i]+=a[i-1]+num;        }        for(int i=0;i<m;i++)        {            getchar();            scanf("%c",&ch);            if(ch=='Q')            {                scanf("%lld%lld",&s,&r);                printf("%lld\n",sum(r)-sum(s-1));            }            else            {                scanf("%lld%lld%lld",&s,&r,&va);                update(s,va);                update(r+1,-va);            }        }    }    return 0;}

线段树:

#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>using namespace std;struct node{    long long int sum,va;}no[300000];void pu(int t){    no[t].sum=no[t<<1].sum+no[t<<1|1].sum;}void build(int l,int r,int s){    no[s].va=0;    if(l==r)    {        scanf("%lld",&no[s].sum);        return ;    }    int mid=(l+r)>>1;    build(l,mid,s<<1);    build(mid+1,r,s<<1|1);    pu(s);}void dd(int t,int m){    if(no[t].va)    {        no[t<<1].va+=no[t].va;        no[t<<1|1].va+=no[t].va;        no[t<<1].sum+=(long long int)(m-(m>>1))*no[t].va;        no[t<<1|1].sum+=(long long int)(m>>1)*no[t].va;        no[t].va=0;    }}long long int query(int l,int r,int ll,int rr,int s){    if(l<=ll&&rr<=r)        return no[s].sum;    int mid=(ll+rr)>>1;    dd(s,rr-ll+1);    long long int ans=0;    if(l<=mid)        ans+=query(l,r,ll,mid,s<<1);    if(r>mid)        ans+=query(l,r,mid+1,rr,s<<1|1);    return ans;}void up(int l,int r,int add,int ll,int rr,int t){    if(l<=ll&&rr<=r)    {        no[t].sum+=(long long int )add*(rr-ll+1);        no[t].va+=add;        return ;    }    dd(t,rr-ll+1);    int mid=(ll+rr)>>1;    if(l<=mid)        up(l,r,add,ll,mid,t<<1);    if(mid<r)        up(l,r,add,mid+1,rr,t<<1|1);    pu(t);}int main(){   int n,q,a,b;   long long int c;   scanf("%d%d",&n,&q);       build(1,n,1);       char s[3];       while(q--)       {           scanf("%s",s);           if(s[0]=='Q')           {               cin>>a>>b;               cout<<query(a,b,1,n,1)<<endl;           }           else if(s[0]=='C')           {               cin>>a>>b>>c;               up(a,b,c,1,n,1);           }       }    return 0;}
阅读全文
0 0