spoj DQUERY - D-query(区间不同数的个数 主席树 or BIT)

题目链接

给出含有n个数字的序列,每次问区间[l,r]不同数的个数。
可以用主席树也可以用树状数组,做法都是同一个原理。从左往右扫一遍,记录每个数上一次出现的位置。当扫到i位置时,
把a[i]上一次出现的位置-1,i这个位置+1。然后对于所有询问区间[x, i]进行回答(BIT区间求和)。主席树也是这个原理,
只是要保存历史版本。

const int maxn = 3e4 + 123;
int ls[maxn*20], rs[maxn*20], root[maxn];
int sum[maxn*20];
int tot;
void build(int& rt, int l, int r) {
    rt = ++ tot;
    sum[rt] = 0;
    if (l == r) return ;
    int m = (l + r) >> 1;
    build(ls[rt], l, m);
    build(rs[rt], m + 1, r);
}
void updata(int last, int& rt, int l, int r, int pos, int val) {
    rt = ++ tot;
    sum[rt] = sum[last] + val;
    ls[rt] = ls[last];
    rs[rt] = rs[last];
    if (l == r) {
        // sum[rt] = val;
        return ;
    }
    int m = (l + r) >> 1;
    if (pos <= m) updata(ls[last], ls[rt], l, m, pos, val);
    else updata(rs[last], rs[rt], m + 1, r, pos, val);
    // sum[rt] = sum[ls[rt]] + sum[rs[rt]];
}
int find(int rt,int l, int r, int pos) {
    int res = 0;
    if (l == r) return sum[rt];
    int m = (l + r) >> 1;
    if (pos <= m) return find(ls[rt], l, m, pos);
    return sum[ls[rt]] + find(rs[rt], m + 1, r, pos);
}
int a[maxn];
int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // ios::sync_with_stdio(false);
    // cout.sync_with_stdio(false);
    // cin.sync_with_stdio(false);

    int n;
    while(~scanf("%d", &n)) {
        tot = 0;
        for (int i = 1;i <= n;++i) {
            scanf("%d", &a[i]);
        }
        build(root[n + 1], 1, n);
        map<int, int> mp;
        for (int i = n;i >= 1;--i) {
            if (mp.find(a[i]) == mp.end()) {
                updata(root[i + 1], root[i], 1, n, i, 1);
            }else {
                int temp;
                updata(root[i + 1], temp, 1, n, mp[a[i]], -1);//隔开中间这个历史版本
                updata(temp, root[i], 1, n, i, 1);
            }
            mp[a[i]] = i;
        }
        int q;scanf("%d", &q);
        while(q--) {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%d\n", find(root[l], 1, n, r));
        }
    }

    // showtime;
    return 0;
}
/*
const int maxn = 1e6 + 10;
struct BIT {
    int sum[maxn];
    void init() {
        memset(sum, 0, sizeof sum);
    }
    void add(int p, int v) {
        while(p < maxn) {
            sum[p] += v;
            p += lowbit(p);
        }
    }
    int find(int p) {
        int res = 0;
        while(p > 0) {
            res += sum[p];
            p -= lowbit(p);
        }
        return res;
    }
}solve;
map<int, int> last;
vector > vec; 
int a[maxn];
int n, m;
int ans[maxn];
int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // ios::sync_with_stdio(false);
    // cout.sync_with_stdio(false);
    // cin.sync_with_stdio(false);

    while(~scanf("%d", &n)) {
        solve.init();
        last.clear();
        vec.clear();
        vec.resize(maxn);
        for (int i = 1;i <= n;++i) {
            scanf("%d", &a[i]);
        }
        scanf("%d", &m);
        for (int i = 1;i <= m;++i) {
            int l, r;
            scanf("%d%d", &l, &r);
            vec[r].push_back(ii(l, i));
        }
        for (int i = 1;i <= n;++i) {
            if (last[a[i]]) solve.add(last[a[i]], -1);
            last[a[i]] = i;
            solve.add(i, 1);
            for (auto x : vec[i]) {
                int idx = x.second;
                int l = x.first;
                ans[idx] = solve.find(i) - solve.find(l - 1);
                // debug(idx);
            }
        }
        for (int i = 1;i <= m;++i)
            printf("%d\n", ans[i]);
    }

    // showtime;
    return 0;
}
*/

/*
const int maxn =3e4 + 123;
int sum[maxn*20], ls[maxn*20], rs[maxn*20], root[maxn];
int a[maxn];
int tot;
int n;
void build(int& rt,int l, int r) {
    rt = ++tot;
    sum[rt] = 0;
    if (l == r) return ;
    int m = (l + r) >> 1;
    build(ls[rt], l, m);
    build(rs[rt], m + 1, r);
}
void updata(int last, int& rt,int l, int r, int pos, int val) {
    rt = ++tot;
    //从上一个线断树版本中复制数据
    sum[rt] = sum[last] + val;
    ls[rt] = ls[last];
    rs[rt] = rs[last];
    if (l == r) return ;
    int m = (l + r) >> 1;
    if (pos <= m) updata(ls[last], ls[rt], l, m, pos, val);
    else updata(rs[last], rs[rt], m + 1, r, pos, val);
}
int find(int pos, int rt, int l, int r) {
    if (l == r) return sum[rt];
    int m = (l + r) >> 1;
    if (pos <= m) return find(pos, ls[rt], l, m) + sum[rs[rt]];
    return find(pos, rs[rt], m + 1, r);
}

int main(int argc, const char * argv[])
{    
    // freopen("in.txt","r",stdin);
    // freopen("out.txt","w",stdout);
    // ios::sync_with_stdio(false);
    // cout.sync_with_stdio(false);
    // cin.sync_with_stdio(false);

    while(~scanf("%d", &n)) {
        for (int i = 1;i <= n;++i)
            scanf("%d", &a[i]);
        map<int, int> mp;
        build(root[0], 1, n);
        for (int i = 1;i <= n;++i) {
            if (mp.find(a[i]) == mp.end()) {
                updata(root[i - 1], root[i], 1, n, i, 1);
            }else {
                int temp;
                updata(root[i - 1], temp, 1, n, mp[a[i]], -1);
                updata(temp, root[i], 1, n, i, 1);
            }
            mp[a[i]] = i;
        }
        int q;scanf("%d", &q);
        while(q--) {
            int l, r;
            scanf("%d%d", &l, &r);
            printf("%d\n", find(l, root[r], 1, n));
        }
    }

    // showtime;
    return 0;
}
*/

你可能感兴趣的:(数据结构-线段树,数据结构-树状数组)