标签:
题目大意:
f(l,r)=∑ri=l ∑rj=i gcd(ai,ai+1....aj)
求解多个区间 l , r 对应的f(l,r)值
这里首先要知道一个数的因子个数不超过log2(n)个,所以作为一个int整数来说,对应求得的最多只有31种gcd值
那么线段树上就可以维护这样的31种gcd值,并记录他们对应的数量
因为需要合并,所以要记录从左到右,和从右到左两种情况
这里我们其实很容易发现你一个个添加数的时候必然越往后区间段的gcd值越小,所以你保存进数组中对应的标号即为对应第几大的gcd值
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 5 using namespace std; 6 #define N 10010 7 #define ls o<<1 8 #define rs o<<1|1 9 #define LL long long 10 #define M int m=(l+r)>>1 11 12 int val[N] , n , q , s , t; 13 14 int gcd(int a , int b){return b==0?a:gcd(b , a%b);} 15 16 struct Node{ 17 int lf[32] , rg[32] , cntl , cntr , nl[32] , nr[32] ; 18 LL sum; 19 }tree[N<<2] , ans; 20 21 Node Union(Node a , Node b) 22 { 23 //a是b左侧的区间节点 24 Node ret; 25 ret.sum = a.sum+b.sum; 26 for(int i=1 ; i<=a.cntr ; i++){ 27 int k = a.rg[i]; 28 for(int j=1 ; j<=b.cntl ; j++){ 29 int tmp = gcd(k , b.lf[j]); 30 ret.sum += (LL)tmp*a.nr[i]*b.nl[j]; 31 } 32 } 33 //更新从右侧出发的 34 for(int i=1 ; i<=b.cntr ; i++) ret.rg[i] = b.rg[i] , ret.nr[i] = b.nr[i]; 35 int k = b.rg[b.cntr] , pos=b.cntr; 36 for(int i=1 ; i<=a.cntr ; i++){ 37 int tmp = gcd(k , a.rg[i]); 38 if(tmp == ret.rg[pos]) ret.nr[pos] += a.nr[i]; 39 else{ 40 pos++; 41 ret.nr[pos] = a.nr[i]; 42 ret.rg[pos] = tmp; 43 } 44 } 45 ret.cntr = pos; 46 47 //更新从左侧出发的 48 for(int i=1 ; i<=a.cntl ; i++) ret.lf[i] = a.lf[i] , ret.nl[i] = a.nl[i]; 49 k = a.lf[a.cntl] , pos = a.cntl; 50 for(int i=1 ; i<=b.cntl ; i++){ 51 int tmp = gcd(k , b.lf[i]); 52 if(tmp == ret.lf[pos]) ret.nl[pos] += b.nl[i]; 53 else{ 54 pos++; 55 ret.nl[pos] = b.nl[i]; 56 ret.lf[pos] = tmp; 57 } 58 } 59 ret.cntl = pos; 60 return ret; 61 } 62 63 void build(int o , int l , int r) 64 { 65 if(l==r){ 66 tree[o].cntl = tree[o].cntr = 1; 67 tree[o].sum = tree[o].lf[1] = tree[o].rg[1] = val[l]; 68 tree[o].nl[1] = tree[o].nr[1] = 1; 69 return ; 70 } 71 M; 72 build(ls , l , m); 73 build(rs , m+1 , r); 74 tree[o] = Union(tree[ls] , tree[rs]); 75 } 76 77 void query(int o , int l , int r , int s , int t) 78 { 79 if(l>=s && r<=t){ 80 if(l==s) ans = tree[o]; 81 else ans = Union(ans , tree[o]); 82 return ; 83 } 84 M; 85 if(m>=s) query(ls , l , m , s , t); 86 if(m<t) query(rs , m+1 , r , s , t); 87 } 88 89 int main() 90 { 91 // freopen("in.txt" , "r" , stdin); 92 int T; 93 scanf("%d" , &T); 94 while(T--){ 95 scanf("%d" , &n); 96 for(int i=1 ; i<=n ; i++) scanf("%d" , &val[i]); 97 build(1,1,n); 98 // cout<<"in: "<<endl; 99 scanf("%d" , &q); 100 while(q--){ 101 scanf("%d%d" , &s , &t); 102 query(1 , 1 , n , s , t); 103 printf("%I64d\n" , ans.sum); 104 } 105 } 106 return 0; 107 }
标签:
原文地址:http://www.cnblogs.com/CSU3901130321/p/4733701.html