2013 Asia Regional Contest Problem H --- Number Squence (树状数组 + 离线)

来源:互联网 发布:大连知行中学中考成绩 编辑:程序博客网 时间:2024/05/29 03:42

链接:  http://acm.hrbust.edu.cn/index.php?m=ProblemSet&a=showProblem&problem_id=1792

Description

Ikki最近又喜欢上了数列游戏,她现在想出个问题考考你,问题是这样的:

首先给你一个由n个整数组成的序列然后Ikki会给出一系列的提问:知道了区间的两个端点s和e,那么这个区间内有多少个不同的数字?

Input

多组测试数据,处理到文件结束,对于每组数据:

第一行输入两个整数n,q分别表示序列中数的个数和Ikki提问的次数

(0<n≤100000,0<q≤100000)。

第二行输入n个整数xi~xn表示序列中每个数的大小。(0 <= x <= 109 )

接下来的q行每行输入两个正整数a,b(a≤b)表示询问的区间为[a,b]。(序列下标从1开始)

Output

对于每组测试数据,输出q行依次表示每个提问的答案。

Sample Input

6 3
1 2 1 2 3 4
1 2
1 3
2 5

Sample Output
2
2
3


分析:

我们可以将查询区间按右端点排序,从左向右枚举i,维护一个树状数组,其中getsum(k)表示从k到i不同的数字有多少个,考虑到将第i个数字加入,这时候,树状数组里面发生改变的仅仅是
last[v] +1 到 i 这个区间的getsum()值,其中v是第i位数字,last[v]表示v这个数上次出线的位置,如果没有出现就为0。所以,我们把树状数组last[v]+1这个位置的值+1,把i+1这个位置的值-1,这样求和的时候,只要是左端点在last[v]+1之后的(包括自己),就能将v这点给包括进来了。然后枚举到i之后,我们考虑右端点是i的全部查询,对其左端点在树状数组中求和就可以了。



代码:

#include <cstdio>#include <cstring>#include <algorithm>#include <ctime>#define MAXN 100005#define RST(N)memset(N, 0, sizeof(N))using namespace std;struct Node{    int l, r;    int x;}q[MAXN];int n, Q, pre[1000001], val[MAXN], tre[MAXN];int tmp[MAXN], xu[MAXN], p[MAXN], res[MAXN], a, b;bool cmp(Node a, Node b) { return a.r < b.r; }inline int lowbit(int x) { return x & (-x); }void add(int pos, int x){    while(pos <= n) {        tre[pos] += x;        pos += lowbit(pos);    }}int getsum(int pos){    int sum = 0;    while (pos > 0) {        sum += tre[pos];        pos -= lowbit(pos);    }    return sum;}int bin_search(int x){    int low = 1, high = n, mid;    while(low <= high) {        mid = (low + high) >> 1;        if(tmp[mid] > x) high = mid - 1;        else if(tmp[mid] < x) low = mid + 1;        else return xu[mid];    }}void Init(){    sort(tmp+1, tmp+n+1);    int m = 1;    xu[1] = 1;    for(int i=2; i<=n; i++) {        if(xu[i] != xu[i-1]) xu[i] = ++m;        else xu[i] = m;    }    for(int i=1; i<=n; i++) val[i] = bin_search(val[i]);    RST(tre), RST(p);}void solve(int Q){    int m = 0;    for(int i=1; i<=n; i++) {        pre[i] = p[val[i]];        p[val[i]] = i;    }    for(int i=1; i<=n; i++) {        add(pre[i]+1, 1);        add(i+1, -1);        while(m < Q && q[m].r == i) {            res[q[m].x] = getsum(q[m].l);            m++;        }    }    for(int i=0; i<Q; i++) printf("%d\n",res[i]);}int main(){    while(~scanf("%d %d", &n, &Q)) {        for(int i=1; i<=n; i++) {            scanf("%d", &val[i]);            tmp[i] = val[i];            xu[i] = i;        }        Init();        for(int i=0; i<Q; i++) {            scanf("%d %d", &q[i].l, &q[i].r);            q[i].x = i;        }        sort(q, q+Q, cmp);        solve(Q);    }    return 0;}




0 0
原创粉丝点击