主要是线段树上的二分,线段树存区间最小值
每次找小于等于p的值,先在左边找,然后在右找,l,r为要找的区间
找到之后,该值的位置设为pos,P模上这个值,然后再找pos+1,r,直到找不到就输出就完了
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <vector>
#include <cstdio>
#include <bitset>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define LL long long
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
const int maxn=1e5+7;
int sum[maxn<<2];
int a[maxn];
int x,y,n,m,t;
void pushup(int rt){
sum[rt]=min(sum[rt<<1],sum[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l==r){
scanf("%d",&sum[rt]);
a[l]=sum[rt];
return;
}
int mid=(r+l)>>1;
build(lson);
build(rson);
pushup(rt);
}
int query(int l,int r,int ll,int rr,int rt,int k){
if(sum[rt]>k) return rr+1;
int mid=(r+l)>>1,res;
if(ll<=l&&rr>=r){
if(l==r) return l;
if(sum[rt<<1]<=k) return query(l,mid,ll,rr,rt<<1,k);
else return query(mid+1,r,ll,rr,rt<<1|1,k);
}
if(ll<=mid){
res=query(l,mid,ll,rr,rt<<1,k);
if(res<=rr) return res;
}
if(rr>mid){
res=query(mid+1,r,ll,rr,rt<<1|1,k);
if(res<=rr) return res;
}
return rr+1;
}
int main(){
scanf("%d",&t);
while(t--){
scanf("%d",&n);
build(1,n,1);
scanf("%d",&m);
while(m--){
scanf("%d%d",&x,&y);
int ans=a[x];
while(x<y){
int q=query(1,n,x+1,y,1,ans);
if(q<=y) ans%=a[q];
x=q;
}
printf("%d\n",ans);
}
}
}