一个长度为n的数组 每次对lr区间进行修改 如果要修改i 则对i i*2 i*3...都修改 最后单点查询值
思想是利用树状数组维护每一个区间的更新值 查询的时候得出这个点的所有因子的查询值的和 加上这个点的最初值
因为对树状数组理解不深再次错过绝杀...
由于是维护每个点的修改量 所以每次修改 都进行add(l,val) add(r+1,-val)
这时候 如果要求单点的修改值 需要sum(x) 而非sum(x)-sum(x-1)
因为没有将初值进行add 所以c数组存放的其实不是一个前缀和 而是一个差分 差分的前缀和就是差分值
#include<stdio.h> #include<string.h> #include<algorithm> #include<math.h> #include<map> #include<vector> #include<queue> using namespace std; #define L long long #define pb push_back L n ; L a[300050] ; vector<L >v[1000050] ; L c[3000050] ; L lowbit(L x){ return (x&-x); } void add(L x,L w) { while(x<=n) { c[x]+=w; x+=lowbit(x); } } L sum(L x) { L tot=0; while(x) { tot+=c[x]; x-=lowbit(x); } return tot; } int main(){ scanf("%lld",&n); for(L i = 1; i <= n ; i ++ ) scanf("%lld",&a[i]); for(L i = 1; i <= n ; i ++ ){ for(L j = 1; j * i <= n ; j ++) { v[j*i].pb(i) ; } } memset(c,0,sizeof(c)); L q; scanf("%lld",&q); while(q--){ L op; scanf("%lld",&op); if(op==2){ L l , r; L val; scanf("%lld%lld%lld",&l,&r,&val); add(l,val); add(r+1,-val); } else { L w; scanf("%lld",&w); L ans=0; for(L i=0;i<v[w].size();i++){ L x=v[w][i]; ans += sum(x) ; } printf("%lld ",ans+a[w]); } } }
..我的绝杀..