hdu5381The sum of gcd 线段树+set

来源:互联网 发布:美亚海淘宝宝用品清单 编辑:程序博客网 时间:2024/06/05 11:47
//f(l,r)=∑(i=l~r)∑j=(i~r)gcd(ai,ai+1....aj)//可以知道每添加一个新的数i,添加了i个区间//而确定了右端点的所有数最多有log(a[i])个//因为从右往前走,每次最少除2//所以可以先将其离线//然后从前到后加入ai用set存入以i为最后一个区间的所有区间//中所有不同的gcd,每个gcd的个数//然后用线段树进行成段的更新#include<cstdio>#include<string>#include<iostream>#include<vector>#include<set>using namespace std ;#define left v<<1#define right v<<1|1const int maxn = 1e4+10 ;typedef long long  ll ;vector<pair<int , int> >vec[maxn] ;ll ans[maxn] ;int a[maxn] ;int gcd(int a , int b){    if(b==0)return a ;    return gcd(b , a%b) ;};struct T{    int l , r ;    ll va ;    ll la ;}tree[maxn<<2];void push_down(int v){    if(tree[v].la)    {        ll tmp =  tree[v].la ;        tree[left].va += tmp*(tree[left].r - tree[left].l + 1) ;        tree[right].va += tmp*(tree[right].r - tree[right].l + 1) ;        tree[left].la += tmp ;        tree[right].la += tmp ;        tree[v].la = 0 ;    }}void push_up(int v){    tree[v].va = tree[left].va + tree[right].va ;}void build(int l , int r , int v){    tree[v].l = l  ;    tree[v].r = r ;    tree[v].la = 0 ;    if(l == r)    {        tree[v].va = 0 ;        return  ;    }    int mid = (l + r) >> 1 ;    build(l , mid , left) ;    build(mid+1 , r , right) ;}void update(int l , int r , int v , ll c){    if(l <= tree[v].l &&  tree[v].r <= r)    {        tree[v].va += c*(tree[v].r - tree[v].l + 1) ;        tree[v].la += c ;        return ;    }    push_down(v) ;    int mid = (tree[v].l + tree[v].r) >> 1 ;    if(l <= mid)    update(l , r , left , c)     ;    if(r > mid)    update(l , r , right , c) ;    push_up(v) ;}ll  query(int l , int r , int v){    if(l <= tree[v].l && tree[v].r <= r)     return tree[v].va ;    push_down(v) ;    int mid = (tree[v].l + tree[v].r) >> 1 ;    ll ans = 0 ;    if(l <= mid)ans += query(l , r , left) ;    if(r > mid)ans += query(l , r , right) ;    push_up(v) ;    return ans ;}int main(){    //freopen("d:\\in.txt" , "r" , stdin) ;    int t ;    scanf("%d" , &t) ;    while(t--)    {        int n ;        scanf("%d" , &n) ;        for(int i = 1;i <= n;i++)        {            scanf("%d" , &a[i]) ;            vec[i].clear() ;        }        int q ;        scanf("%d" , &q) ;        for(int i = 1;i  <= q;i++)        {            int l , r ;            scanf("%d%d" , &l , &r) ;            vec[r].push_back(make_pair(l , i)) ;        }        set<pair<int , int> >::iterator it ;        set<pair<int , int> > se[2] ;        se[0].clear() ;se[1].clear() ;        build(1 , n , 1) ;        for(int i = 1;i <= n;i++)        {            int sum = 0 ;            int pos = -1 ;            int l = 1 ;            se[(i+1)%2].clear() ;            for(it = se[i%2].begin() ;it != se[i%2].end();it++)            {                int tmp = gcd(it->first , a[i]) ;                if(pos == -1 || tmp == pos){                    pos = tmp ;                    sum += it->second ;                }                else                {                    se[(i+1)%2].insert(make_pair(pos , sum)) ;                    update(l , l + sum -1 , 1 , pos) ;                    l += sum ;                    pos = tmp ;                    sum = it->second ;                }            }            if(pos == -1)            {                update(1 , 1 , 1 , a[i]) ;                se[(i+1)%2].insert(make_pair(a[i] , 1)) ;            }            else if(pos == a[i])            {                update(l , l+sum , 1 , pos) ;                se[(i+1)%2].insert(make_pair(pos , sum+1)) ;            }            else            {                update(l , l + sum - 1 , 1 , pos) ;                se[(i+1)%2].insert(make_pair(pos , sum)) ;                update(l+sum , l+sum , 1 , a[i]) ;                se[(i+1)%2].insert(make_pair(a[i] , 1)) ;            }            for(int j = 0;j < vec[i].size();j++)            ans[vec[i][j].second] = query(vec[i][j].first , i,1) ;        }        for(int i = 1;i <= q;i++)       printf("%lld\n" , ans[i]) ;    }    return  0 ;}

0 0
原创粉丝点击