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



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

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

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

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

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

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

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

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define eps 1e-6
#define LL long long
#define pii (pair)
//#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 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;
}

你可能感兴趣的:(程序设计竞赛)