链接: 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
分析:
代码:
#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; }