题意:
给你一个长度为
n
n
n的数组,每次询问给出一个区间
[
l
,
r
]
[l,r]
[l,r],问你用当前的区间内的任意个数,不能组成的最小的正整数是多少?
思路:
这道题其实需要解决的就是,怎么快速求出来,这个不能表示的数是多少,我们这样考虑,假设把当前给定的区间的内的数
a
l
,
a
l
+
1
,
.
.
.
.
,
a
r
a_l,a_{l+1},....,a_r
al,al+1,....,ar按照从小到大的顺序排起来,考虑
s
i
s_i
si为这组序列前
i
i
i个数的和,我们如果能找到,
s
i
+
1
<
a
i
+
1
s_i+1 < a_{i+1}
si+1<ai+1,是不是就代表这个
s
i
+
1
s_i+1
si+1就是我们表示不出来的数呢,因为前面的那些小的数加起来都凑不够,而后面的任意一个数又比它大,所以肯定是凑不出来的。
类似于一种套路吧应该,知道了这个之后,我们能否快速求出来,区间不能表示的数呢。
也就是说假如一个数
a
i
+
1
≤
s
i
+
1
a_{i+1} \leq s_i + 1
ai+1≤si+1,那么我们就可以把它加入到我这个和中,所以对于每个
s
i
+
1
s_i + 1
si+1,我们只需要找出来当前这个区间内
≤
s
i
+
1
\leq s_i+1
≤si+1的所有的数有哪些,然后把他们的和加入到
s
i
s_i
si中即可,因为这些一定合法。
所以我们只需要找到能够快速查询区间内小于等于某个数的所有数的和的这样一种工具即可,主席树即可完成。
时间复杂度的话,因为每次迭代变大 s i s_i si最小也是增加一倍,所以最坏的复杂度也就是 l o g log log级的,所以是可以接受的。
我如果离散化存 a i a_i ai的话,会MLE,不知道为什么,但因为是主席树查值域,所以不用离散化也可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pb push_back
#define eb emplace_back
#define MP make_pair
#define pii pair<int,int>
#define pll pair<ll,ll>
#define lson rt<<1
#define rson rt<<1|1
#define CLOSE std::ios::sync_with_stdio(false)
#define sz(x) (int)(x).size()
typedef long long ll;
typedef double db;
const int INF = 0x3f3f3f3f;
const db eps = 1e-6;
const int N = 1e6 + 10;
//知道某个区间内不超过某个数的所有数的和即可
int n,m,root[N * 40],tot;
ll a[N];
struct CT {
int l,r;
ll sum;
}tree[N * 40];
void pushup(int now) {
tree[now].sum = tree[tree[now].l].sum + tree[tree[now].r].sum;
}
void build(int &now,int l,int r) {
tree[now = ++tot];
tree[now].l = l,tree[now].r = r;
if(l == r) {
tree[now].sum = 0; return ;
}
int mid = (l + r) >> 1;
build(tree[now].l,l,mid); build(tree[now].r,mid+1,r);
pushup(now);
}
void modify(int &now,int pre,int l,int r,int pos,ll v) {
tree[now = ++tot] = tree[pre];
if(l == r) {
tree[now].sum += v; return ;
}
int mid = (l + r) >> 1;
if(pos <= mid) modify(tree[now].l,tree[pre].l,l,mid,pos,v);
else modify(tree[now].r,tree[pre].r,mid+1,r,pos,v);
pushup(now);
}
ll query(int now,int pre,int l,int r,int L,int R) {
if(l >= L && r <= R) return tree[now].sum - tree[pre].sum;
int mid = (l + r) >> 1;
ll ans = 0;
if(L <= mid) ans += query(tree[now].l,tree[pre].l,l,mid,L,R);
if(R > mid) ans += query(tree[now].r,tree[pre].r,mid+1,r,L,R);
return ans;
}
int lsh[N],cnt;
int getid(ll x) {
return lower_bound(lsh + 1,lsh + 1 + cnt,x) - lsh;
}
// std::map<ll,bool>vis;
signed main() {
scanf("%lld%lld",&n,&m);
for(int i = 1;i <= n;i ++) {
scanf("%lld",&a[i]);
}
// sort(lsh + 1,lsh + 1 + n);
// cnt = unique(lsh + 1,lsh + 1 + cnt) - lsh - 1;
// build(root[0],1,(int)1e9);
// cout << "---------------\n";
for(int i = 1;i <= n;i ++) {
// int p = getid(a[i]);
modify(root[i],root[i-1],1,(int)1e9,a[i],a[i]);
}
// sort(a + 1,a + 1 + n);
int l,r;
ll ans = 0;
for(int _ = 1;_ <= m;_ ++) {
scanf("%lld%lld",&l,&r);
l = (l + ans) % n + 1;
r = (r + ans) % n + 1;
if(l > r) swap(l,r);
// cout << l << ' ' << r << '\n';
ll f = 0,ff;
while(true) {
ll ff = query(root[r],root[l-1],1,(int)1e9,1,f + 1);
// cout << ff << "***\n";
if(ff == f) break;
f = ff;
// cout << f << "***\n";
}
ans = f + 1;
printf("%lld\n",ans);
}
return 0;
}