【题目链接】 http://acm.timus.ru/problem.aspx?space=1&num=2062
【题目大意】
给出两个操作,操作一给出区间[l,r],对l到r中的每一个下标i,
i,2*i,3*i……位置都增加x,操作二要求查询一个位置的当前值
【题解】
在修改的时候,我们将增量只标识在i上,查询的时候,查询下标的因子和即可。
考虑到这种查询方法需要sqrt(n)枚举判断因子,用二叉数据结构可能会超时,
因此我们用分块nsqrt(n)修改,O(1)查询特定位置。
【代码】
#include <cstdio> #include <algorithm> #include <cmath> #include <cstring> using namespace std; typedef long long LL; const int MAX_SIZE=550,MAX_N=300010; LL block[MAX_SIZE],u[MAX_SIZE][MAX_SIZE]; int n,m,a[MAX_N],op,x,l,r,size; void add(int l,int r,int v){ int L=l/size,R=r/size; if(L==R)for(int i=l%size;i<=r%size;i++)u[L][i]+=v; else{ for(int i=l%size;i<size;i++)u[L][i]+=v; for(int i=L+1;i<R;i++)block[i]+=v; for(int i=0;i<=r%size;i++)u[R][i]+=v; } } LL query(int x){ LL ans=0; for(int i=1;i*i<=x;i++){ if(x%i==0){ int t=i-1; ans+=block[t/size]+u[t/size][t%size]; if(i*i!=x){ int t=x/i-1; ans+=block[t/size]+u[t/size][t%size]; } } }return ans; } int main(){ while(~scanf("%d",&n)){ memset(block,0,sizeof(block)); memset(u,0,sizeof(u)); for(int i=1;i<=n;i++)scanf("%d",&a[i]); scanf("%d",&m); size=sqrt(n); while(m--){ scanf("%d",&op); if(op==1){ scanf("%d",&x); printf("%lld ",query(x)+a[x]); }else{ scanf("%d%d%d",&l,&r,&x); add(--l,--r,x); } } }return 0; }