【分析】把每个查询范围画出来就是一个倒三角,然后可以用莫队算法,关键就是单步转移;因为对于任意一个数已知gcd最多只有log(ai)种数字,所以用st预处理出每个点往右和往左求出的一段gcd值最多只有log(ai)种;这样就可以用log(ai)的复杂度转移,莫队复杂度就是q*sqrt(n)*log(ai);而前面预处理需要二分来加速,这样配合st就是n*logn的(开始用线段树n*logn*logn预处理无线T,还是线段树常数太大)。
【AC CODE】390ms
#include <bits/stdc++.h> using namespace std; typedef long long LL; #define rep(i,a,n) for(int i = a; i < n; i++) #define repe(i,a,n) for(int i = a; i <= n; i++) #define per(i,n,a) for(int i = n; i >= a; i--) #define clc(a,b) memset(a,b,sizeof(a)) const int INF = 0x3f3f3f3f, MAXN = 10000+10, MAXIN = 10000,MAXOUT = 10000; char buf[MAXIN], *ps = buf, *pe = buf+1; inline void rnext(){ if(++ps == pe) pe = (ps = buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin); } template <class T> inline bool in_int(T &ans) { ans = 0; T f = 1; if(ps == pe) return false; do{ rnext(); if('-' == *ps) f = -1;} while(!isdigit(*ps) && ps != pe); if(ps == pe) return false; do{ ans = (ans<<1)+(ans<<3)+*ps-48;rnext();}while(isdigit(*ps) && ps != pe); ans *= f; return true; } char bufout[MAXOUT], outtmp[50],*pout = bufout, *pend = bufout+MAXOUT; inline void write(){ fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;}/*必须在程序结束时加 write()*/ inline void out_char(char c){ *(pout++) = c;if(pout == pend) write();} inline void out_str(char *s) { while(*s){ *(pout++) = *(s++); if(pout == pend) write(); } } template <class T> inline void out_int(T x) { if(!x){ out_char('0');return;} if(x < 0) x = -x,out_char('-'); int len = 0; while(x){ outtmp[len++] = x%10+48; x /= 10;} outtmp[len] = 0; for(int i = 0, j = len-1; i < j; i++,j--) swap(outtmp[i],outtmp[j]); out_str(outtmp); } int a[MAXN],n; int gcd(int a, int b) { while(b) { a %= b; if(a < b) swap(a,b); } return a; } int dp[MAXN][20]; void st_init(int n) { repe(i,1,n) dp[i][0] = a[i-1];//下标从1开始的 for(int j = 1; (1<<j) <= n; j++) { for(int i = 1; i+(1<<j)-1 <= n; i++)//下标从1开始的 dp[i][j] = gcd(dp[i][j-1], dp[i+(1<<(j-1))][j-1]); } } int st(int x, int y) { x++,y++; int k = 0; while((1<<(k+1)) <= y-x+1) k++; return gcd(dp[x][k], dp[y-(1<<k)+1][k]); } struct NODE{ int x,y,id,block; bool operator<(const NODE&t)const{ if(block != t.block) return block < t.block; return y < t.y; } }in[MAXN]; struct P{ int len; LL v[31],cnt[31]; }p[2][MAXN]; int find_r(int v, int l) { int x = l, y = n-1; while(x <= y) { int m = (x+y)>>1; if(st(l,m) >= v) x = m+1; else y = m-1; } return x; } int find_l(int v, int r) { int x = 0,y = r; while(x <= y) { int m = (x+y)>>1; if(st(m,r) >= v) y = m-1; else x = m+1; } return y; } LL ans[MAXN],sum; void update(int tag, bool add, int st, int ed) { int cnt = ed-st+1,tol = 0; P *now = &p[tag][st]; if(tag) now = &p[tag][ed]; while(cnt) { if(cnt >= now->cnt[tol]) { if(add) sum += now->cnt[tol]*now->v[tol]; else sum -= now->cnt[tol]*now->v[tol]; cnt -= now->cnt[tol++]; } else { if(add) sum += now->v[tol]*cnt; else sum -= now->v[tol]*cnt; cnt = 0; } } } int main() { #ifdef SHY freopen("d:\\1.txt", "r", stdin); freopen("d:\\out.txt", "w", stdout); #endif int t; in_int(t); while(t--) { in_int(n); rep(i,0,n) in_int(a[i]); st_init(n); rep(i,0,n) { int pos = i,la = i,v = a[i]; p[0][i].len = 0; while(1) { pos = find_r(v,i); p[0][i].v[p[0][i].len] = v; p[0][i].cnt[p[0][i].len++] = pos-la; if(pos > n-1) break; v = st(i,pos); la = pos; } } rep(i,0,n) { int pos = i,la = i,v = a[i]; p[1][i].len = 0; while(1) { pos = find_l(v,i); p[1][i].v[p[1][i].len] = v; p[1][i].cnt[p[1][i].len++] = la-pos; if(pos < 0) break; v = st(pos,i); la = pos; } } int q, SIZE = sqrt(n+0.5); in_int(q); rep(i,0,q) { in_int(in[i].x), in_int(in[i].y); in[i].x--;in[i].y--; in[i].id = i; in[i].block = in[i].x/SIZE; } sort(in,in+q); sum = a[0]; int x = 0,y = 0; rep(i,0,q) { while(x > in[i].x) { update(0,1,--x,y); //sum += add[0][--x]; } while(y < in[i].y) { update(1,1,x,++y); //sum += add[1][++y]; } while(x < in[i].x) { update(0,0,x++,y); //sum -= add[0][x++]; } while(y > in[i].y) { update(1,0,x,y--); //sum -= add[1][y--]; } ans[in[i].id] = sum; } rep(i,0,q) out_int(ans[i]),out_char('\n'); } write(); return 0; }