【XSY2111】Chef and Churus 分块 树状数组

来源:互联网 发布:睡别人女朋友 知乎 编辑:程序博客网 时间:2024/05/18 01:13

题目描述

  有一个长度为n的数组An个区间[li,ri],有q次操作:

   1 x y:把ax改成y

   2 x y:求第l个区间到第r个区间的区间和的和。

  n,q105,ai109

题解

  分块。

  设si为第i块的所有区间的区间和,di,j为第i块有多少个区间包含了j这个位置。

  修改时修改树状数组和每个区间的区间和。设当前ax=v,则si+=(yv)×di,x

  查询时完整的区间直接查询区间和,不完整的区间就暴力查询。

  设块大小为m,时间复杂度为

T(n)=O(nm+mlogn)

  当m=nlogn
T(n)min=O(nnlogn)

代码

#include<cstdio>#include<cstring>#include<algorithm>#include<cstdlib>#include<ctime>#include<utility>using namespace std;typedef long long ll;typedef unsigned long long ull;typedef pair<int,int> pii;ull c[100010];int a[100010];int n;void add(int x,ull v){    for(;x<=n;x+=x&-x)        c[x]+=v;}ull sum(int x){    ull s=0;    for(;x;x-=x&-x)        s+=c[x];    return s;}int bl;ull s[1010];int d[1010][100010];int l[100010];int r[100010];int block[100010];int left[100010];int right[100010];int main(){    memset(c,0,sizeof c);//  freopen("xsy2111.in","r",stdin);//  freopen("xsy2111.out","w",stdout);    int m;    scanf("%d",&n);    int i;    for(i=1;i<=n;i++)    {        scanf("%d",&a[i]);        add(i,a[i]);    }    bl=100;    m=(n+bl-1)/bl;    for(i=1;i<=n;i++)        block[i]=(i+bl-1)/bl;    for(i=1;i<=m;i++)    {        left[i]=(i-1)*bl+1;        right[i]=min(i*bl,n);    }    for(i=1;i<=n;i++)    {        scanf("%d%d",&l[i],&r[i]);        s[block[i]]+=sum(r[i])-sum(l[i]-1);        d[block[i]][l[i]]++;        if(r[i]<n)            d[block[i]][r[i]+1]--;    }    int j;    for(i=1;i<=m;i++)        for(j=2;j<=n;j++)            d[i][j]+=d[i][j-1];    int q;    scanf("%d",&q);    int op,x,y,k;    for(i=1;i<=q;i++)    {        scanf("%d%d%d",&op,&x,&y);        if(op==1)        {            int v=a[x];            for(j=1;j<=m;j++)                s[j]+=ull(y-v)*d[j][x];            add(x,y-v);            a[x]=y;        }        else        {            ull ans=0;            for(j=block[x];j<=block[y];j++)                if(left[j]>=x&&right[j]<=y)                    ans+=s[j];                else                {                    int mi=max(left[j],x);                    int mx=min(right[j],y);                    for(k=mi;k<=mx;k++)                        ans+=sum(r[k])-sum(l[k]-1);                }            printf("%llu\n",ans);        }    }    return 0;}