SPOJ 3267 DQUERY(主席树在线|树状数组离线)

来源:互联网 发布:手机淘宝卖家怎么直播 编辑:程序博客网 时间:2024/05/16 19:23


题意:给定n个数,m个询问,每次回答某个区间内不相同的元素个数。

思路:这道题很像之前hdu上做过的一道 http://blog.csdn.net/u014664226/article/details/47307779

这是用树状数组离线做的,将询问排序,从头扫一遍,将将当前元素上次的出现的位置减一,本次出现的位置加一,如果该点有询问,记录答案。

今天学习了主席树,又用主席树做了一遍,思路和树状数组差不多。

主席树建新树的时候,如果当前元素出现过,那么把这个元素上次出现的位置减一,然后当前位置加一,如果没出现过就是普通的建树操作。

对于查询[l, r]我们只需要取出第r棵树,然后输出这棵树[l,r]之间的和即可。

这道题两种做法时间复杂度都是O(n*logn)。

#include<cstdio>#include<cstring>#include<cmath>#include<cstdlib>#include<iostream>#include<algorithm>#include<vector>#include<map>#include<queue>#include<stack>#include<string>#include<map>#include<set>#include<ctime>#define eps 1e-6#define LL long long#define pii (pair<int, int>)//#pragma comment(linker, "/STACK:1024000000,1024000000")using namespace std;//const int maxn = 100000 + 100;//const int INF = 0x3f3f3f3f;const int maxn = 50000;const int M = 15*maxn;int n, q, m, tot;int a[maxn];int T[maxn], lson[M], rson[M], c[M];map<int, int> vis;int build(int l, int r) {int root = tot++;c[root] = 0;if(l != r) {int mid = (l+r) >> 1;lson[root] = build(l, mid);rson[root] = build(mid+1, r);}return root;}int Insert(int root, int pos, int val) {int newroot = tot++, tmp = newroot;int l = 1, r = n;c[newroot] = c[root] + val;    while(l < r) {        int mid = (l+r)>>1;        if(pos <= mid) {            lson[newroot] = tot++; rson[newroot] = rson[root];            newroot = lson[newroot]; root = lson[root];            r = mid;        }        else {            rson[newroot] = tot++; lson[newroot] = lson[root];            newroot = rson[newroot]; root = rson[root];            l = mid+1;        }        c[newroot] = c[root] + val;    }return tmp;}int Query(int root, int p, int l, int r) {if(l == p) return c[root];int mid = (l+r) >> 1;int ans = 0;if(p <= mid) return Query(lson[root], p, l, mid) + c[rson[root]];return Query(rson[root], p, mid+1, r);}int main() {    //freopen("input.txt", "r", stdin);    while(cin >> n) {tot = 0;vis.clear();for(int i = 1; i <= n; i++) scanf("%d", &a[i]);T[0] = build(1, n);for(int i = 1; i <= n; i++) {if(!vis.count(a[i])) T[i] = Insert(T[i-1], i, 1), vis[a[i]] = i;else {T[i] = Insert(T[i-1], vis[a[i]], -1);T[i] = Insert(T[i], i, 1);vis[a[i]] = i;}}cin >> q;for(int i = 0; i < q; i++) {int l, r; scanf("%d%d", &l, &r);printf("%d\n", Query(T[r], l, 1, n));}    }    return 0;}

0 0