【题目链接】
https://www.lydsy.com/JudgeOnline/problem.php?id=4408
【题解】
先建出可持久化线段树,查询时查询当前可到达的区间中是否还有其他数,有就更新可到达区间并再次查询,没有就退出。
由于每一次更新的数都大于上一次的区间总长,所以区间长度是指数级增长的(最差是斐波那契数列)。
时间复杂度
O(N∗log2N)
O
(
N
∗
l
o
g
2
N
)
【代码】
/* - - - - - - - - - - - - - - -
User : VanishD
problem : [bzoj4408]
Points : segment tree
- - - - - - - - - - - - - - - */
# include <bits/stdc++.h>
# define ll long long
# define inf 0x3f3f3f3f
# define N 100010
using namespace std;
int read(){
int tmp = 0, fh = 1; char ch = getchar();
while (ch < '0' || ch > '9'){ if (ch == '-') fh = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9'){ tmp = tmp * 10 + ch - '0'; ch = getchar(); }
return tmp * fh;
}
struct Tree{
int pl, pr, num;
}T[N * 50];
const int L = 1, R = 1e9;
int n, q, place, rt[N];
void extend(int &p, int las, int num, int l, int r){
if (!p) p = ++place;
T[p].num = T[las].num + num;
if (l != r){
int mid = (l + r) / 2;
if (mid >= num){
extend(T[p].pl, T[las].pl, num, l, mid);
T[p].pr = T[las].pr;
}
else{
extend(T[p].pr, T[las].pr, num, mid + 1, r);
T[p].pl = T[las].pl;
}
}
}
int query(int pr, int pl, int ql, int qr, int l, int r){
if (ql == l && qr == r) return T[pr].num - T[pl].num;
int mid = (l + r) / 2;
if (mid >= qr) return query(T[pr].pl, T[pl].pl, ql, qr, l, mid);
else if (mid < ql) return query(T[pr].pr, T[pl].pr, ql, qr, mid + 1, r);
else return query(T[pr].pl, T[pl].pl, ql, mid, l, mid) + query(T[pr].pr, T[pl].pr, mid + 1, qr, mid + 1, r);
}
int main(){
// freopen(".in", "r", stdin);
// freopen(".out", "w", stdout);
n = read();
for (int i = 1; i <= n; i++){
int x = read();
extend(rt[i], rt[i - 1], x, L, R);
}
q = read();
for (int i = 1; i <= q; i++){
int l = read(), r = read();
int now = 0, tmp = 1;
while (now != tmp){
now = tmp;
tmp = query(rt[r], rt[l - 1], 1, now, L, R) + 1;
}
printf("%d\n", tmp);
}
return 0;
}