【CODECHEF】Chef and Churus
Description
有一个长度为\(n\)的数组\(A\),有\(n\)个函数,第\(i\)个函数的值为\(\sum_{j=l_i}^{r_i}A_j\)
有两种操作:
①修改\(A_i\)
②询问第\(l\)~\(r\)个函数值的和。
Input
First Line is the size of the array i.e. N
Next Line contains N space separated numbers Ai denoting the array
Next N line follows denoting Li and Ri for each functions.
Next Line contains an integer Q , number of queries to follow.
Next Q line follows , each line containing a query of Type 1 or Type 2.
1 x y : denotes a type 1 query,where x and y are integers
2 m n : denotes a type 2 query where m and n are integers
Output
For each query of type 2 , output as asked above.
说明
\(1 ≤ N ≤ 10^5,1 ≤ A_i ≤ 10^9,1 ≤ L_i ≤ N,L_i ≤ R_i ≤ N,1 ≤ Q ≤ 10^5\)
\(1 ≤ x ≤ N,1 ≤ y ≤ 10^9,1 ≤ m ≤ N,m ≤ n ≤ N\)
一开始想了个做法,大概是把询问放到线段树的节点上,线段树维护区间和,外面用树状数组维护询问前缀和,然后每次修改的时候暴力改修改一条链的线段树节点上对树状数组的贡献。写完了感觉复杂度有点不对,好像是三个\(\log\)的,又好像可以卡,反正T掉了。
然后正解分块的思路真是神仙%%
对\(A\)进行分块,块内维护快内前缀和,块外维护块的前缀和。这样我们单点修改可以\(O(\sqrt n)\)做,但是询问区间和居然是\(O(1)\)的。
然后对询问进行分块,每个块\(i\)维护一个\(dev_{i,j}\)代表块\(i\)中所有函数覆盖了几个\(j\)这个位置,可以差分进行预处理,再维护一个\(sum_i\)表示这一整块的答案。然后我们发现修改的时候遍历一遍所有块就行了,复杂度是\(O(\sqrt n)\)的
询问的时候,整块直接用\(sum\),散块直接暴力查询区间就可以,复杂度\(O(\sqrt n)\)
于是总复杂度是\(O(n\sqrt n)\)
注意开ull
Code:
#include <cstdio>
#include <cmath>
#define ll unsigned long long
const int N=100010;
const int M=320;
ll F[M],f[N],a[N],sum[M];
int L[N],R[N],dev[M][N],Belong[N],ql[N],qr[N],T,num,n,m;
ll ask(int l,int r)//询问区间的和
{
int lp=Belong[l],rp=Belong[r];
if(lp==rp) return f[r]-(l==L[lp]?0:f[l-1]);
return f[R[lp]]-(l==L[lp]?0:f[l-1])+F[rp-1]-F[lp]+f[r];
}
void modify(int x,ll d)
{
int pos=Belong[x];//改数组块
for(int i=x;i<=R[pos];i++)
f[i]+=d-a[x];
for(int i=pos;i<=num;i++)
F[i]+=d-a[x];
for(int i=1;i<=num;i++)//改询问块
sum[i]+=(d-a[x])*dev[i][x];
a[x]=d;
}
ll query(int l,int r)
{
int lp=Belong[l],rp=Belong[r];
ll ret=0;
if(lp==rp)
{
for(int i=l;i<=r;i++)
ret+=ask(ql[i],qr[i]);
}
else
{
for(int i=l;i<=R[lp];i++)
ret+=ask(ql[i],qr[i]);
for(int i=L[rp];i<=r;i++)
ret+=ask(ql[i],qr[i]);
for(int i=lp+1;i<rp;i++)
ret+=sum[i];
}
return ret;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%llu",f+i),a[i]=f[i];
T=sqrt(n)+1;
for(num=1;num*T<=n;num++) L[num]=T*(num-1)+1,R[num]=T*num;--num;
if(R[num]<n) L[num+1]=R[num]+1,R[++num]=n;
for(int i=1;i<=num;i++)
{
Belong[L[i]]=i;
for(int j=L[i]+1;j<=R[i];j++)
f[j]+=f[j-1],Belong[j]=i;
F[i]+=f[R[i]]+F[i-1];
}
for(int i=1;i<=n;i++) scanf("%d%d",ql+i,qr+i);
for(int i=1;i<=num;i++)
{
for(int j=L[i];j<=R[i];j++)
++dev[i][ql[j]],--dev[i][qr[j]+1];
for(int j=1;j<=n;j++)
dev[i][j]+=dev[i][j-1],sum[i]+=1ll*dev[i][j]*a[j];
}
scanf("%d",&m);
for(int op,l,r,i=1;i<=m;i++)
{
scanf("%d%d%d",&op,&l,&r);
if(op==1) modify(l,r);
else printf("%llu\n",query(l,r));
}
return 0;
}
2018.12.13