[bzoj4408][Fjoi 2016]神秘数【线段树】【复杂度分析】

【题目链接】
  https://www.lydsy.com/JudgeOnline/problem.php?id=4408
【题解】
  先建出可持久化线段树,查询时查询当前可到达的区间中是否还有其他数,有就更新可到达区间并再次查询,没有就退出。
  由于每一次更新的数都大于上一次的区间总长,所以区间长度是指数级增长的(最差是斐波那契数列)。
  时间复杂度 O(Nlog2N) O ( N ∗ l o g 2 N )
【代码】

/* - - - - - - - - - - - - - - -
    User :      VanishD
    problem :   [bzoj4408]
    Points :    segment tree
- - - - - - - - - - - - - - - */
# include 
# 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;
}

你可能感兴趣的:(【线段树】,【复杂度分析】)