題意,給一堆數,給你一個區間,求這個區間第一個數 模 第二個數 模 第三個數 ....模到這個區間最後一個數,最後值是多少,有多次詢問。然後很明顯的,一個數摸一個比他小的數就變小了,比他大的數,他不變,所以總是要找小的數,如果能知道一個數在他後面第一個比他小的數u,然後取模,再去找u後面比他小的第一個數,再取模,這樣子能跳過很多不用的區間。那麼問題來了,如何快速知道一個數之後第一個比他小的數呢??單調棧,ok,解決了。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <stack>
using namespace std;
int n, m;
int next[100005];
struct node
{
int pos;
int val;
}a[100005], tmp;
stack<node> s;
int main(void)
{
int T;
scanf("%d", &T);
for (int i = 1; i < 100005; i++)
a[i].pos = i;
tmp.pos = 0;
tmp.val = 0;
while (T--)
{
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i].val);
scanf("%d", &m);
memset(::next, 0x3f3f3f3f, sizeof ::next);
while (!s.empty()) s.pop();
s.push(tmp);
for (int i = 1; i <= n; i++)
{
while (s.top().val > a[i].val)
{
::next[s.top().pos] = i;
s.pop();
}
s.push(a[i]);
}
int l, r;
for (int i = 0; i < m; i++)
{
scanf("%d%d", &l, &r);
int ans = a[l].val;
for (int j = ::next[l]; j <= r; j = ::next[j])
{
if (ans == 1 || ans == 0) break;
ans %= a[j].val;
}
printf("%d\n", ans);
}
}
return 0;
}