解法:
首先經過一段時間的思考後我們可以發現一個數取模只會受到小於等於它的模數的影響,而且取模的次數大概是log級別的,因爲取一次至少減半,所以我們可以有一個簡單的想法,就是找到這個數右邊第一個小於等於它的數進行取模。然後我們用較爲暴力的方法,二分加線段樹,過去了。(我寫的T了,好像常數太大,隊友的過了,學習了一發姿勢,二分嵌在線段樹裏寫)。還要注意是兩個端點都相等的時候進行操作,不是包含,因爲涉及到左右關係啥的。要被正好頂着左邊或者右邊覆蓋。
代碼:
//
// main.cpp
// 1008
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define lson o * 2,l,m
#define rson o * 2 + 1,m + 1,r
const int maxn = 1e5 + 5;
int minv[maxn << 2];
int a[maxn];
void build(int o,int l,int r){
if(l == r){
minv[o] = a[l];
return;
}
int m = (l + r) >> 1;
build(lson);
build(rson);
minv[o] = min(minv[o * 2],minv[o * 2 + 1]);
}
int query(int o,int l,int r,int ql,int qr,int p){
if(p == 0) return 0;
if(l == ql && r == qr){
if(minv[o] > p) return p;
int now,now_l,now_r,now_m;
now_l = l;
now_r = r;
now = o;
while(now_l < now_r){
now_m = (now_l + now_r) >> 1;
if(minv[now * 2] <= p){
now = now * 2;
now_r = now_m;
}else{
now = now * 2 + 1;
now_l = now_m + 1;
}
}
p %= minv[now];
if(p == 0) return 0;
return query(o,l,r,now_l + 1,r,p);
}
int m = (l + r) >> 1;
if (ql <= m && minv[o * 2] <= p) p = query(o * 2,l,m,ql,min(qr,m),p);
if (p == 0) return 0;
if (qr > m && minv[o * 2 + 1] <= p) p = query(o * 2 + 1,m + 1,r,max(ql,m + 1),qr,p);
return p;
}
int n,m;
int main(int argc, const char * argv[]) {
int T;
cin >> T;
while(T--){
cin >> n;
for(int i = 1;i <= n;i++){
scanf("%d",a + i);
}
build(1,1,n);
cin >> m;
for(int i = 1;i <= m;i++){
int l,r;
scanf("%d%d",&l,&r);
if(l == r) printf("%d\n",a[l]);
else{
printf("%d\n",query(1, 1, n, l + 1, r, a[l]));
}
}
}
return 0;
}