URAL 2062 树状数组

一个长度为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\n",ans+a[w]);
        }
    }
}

..我的绝杀..

 

posted @ 2017-02-16 17:42  天翎月  阅读(211)  评论(0编辑  收藏  举报