牛客网多校训练第一场 J - Different Integers(树状数组 + 问题转换)

链接:

https://www.nowcoder.com/acm/contest/139/J

 

题意:

给出n个整数的序列a(1≤ai≤n)和q个询问(1≤n,q≤1e5),每个询问包含两个整数L和R(1≤L,R≤n)。
对于每个询问,输出a[1...L]和a[R...n]的不同数字的个数。

 

分析:

将原数组复制一份拼接到末尾,把询问a[1...L]和a[R...n]转换为询问a[R...L+n]。
设kind[i]为a[1...i]出现的数字种类,
则询问a[L...R]的答案为 kind[R] - kind[L-1] +(a[1...L-1]和a[L...R]同时出现的数字种类)。
可以用树状数组维护a[1...L-1]和a[L...R]同时出现的数字种类。
如果a[i]在区间1...L-1出现过,则对应的树状数组位置的值应为1。查询时只需查询区间L...R。
可以对询问区间按左端点排序,左端点每次右移时把对应的数的下一个位置在树状数组里加1即可。

 

代码:

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int MAXS = 1e6 + 5;
 7 int sf[MAXS];
 8 void add(int p, int v, int n) {
 9     while(p <= n) sf[p] += v, p += p&-p;
10 }
11 int sum(int p) {
12     int res = 0;
13     while(p) res += sf[p], p -= p&-p;
14     return res;
15 }
16 
17 struct REGION {
18     int L, R, id;
19     bool operator < (const REGION& that) const {
20         return L < that.L;
21     }
22 } r[MAXS];
23 int a[MAXS], kind[MAXS], nxt[MAXS], rec[MAXS], ans[MAXS];
24 
25 int main() {
26     int n, q;
27     while(~scanf("%d%d", &n, &q)) {
28         for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
29         for(int i = 0; i < q; i++) {
30             scanf("%d%d", &r[i].R, &r[i].L);
31             r[i].R += n;
32             r[i].id = i;
33         }
34         memcpy(a+n+1, a+1, n*sizeof(int));
35         n *= 2;
36         memset(rec, false, sizeof(rec));
37         for(int i = 1; i <= n; i++) {
38             if(rec[a[i]]) kind[i] = kind[i-1];
39             else kind[i] = kind[i-1] + 1, rec[a[i]] = true;
40         }
41         memset(rec, false, sizeof(rec));
42         for(int i = n; i > 0; i--) {
43             nxt[i] = rec[a[i]];
44             rec[a[i]] = i;
45         }
46         sort(r, r + q);
47         memset(sf, 0, sizeof(sf));
48         for(int p = 1, i = 0; i < q; i++) {
49             while(p < r[i].L) add(nxt[p], 1, n), p++;
50             ans[r[i].id] = kind[r[i].R]-kind[r[i].L-1] + sum(r[i].R)-sum(r[i].L-1);
51         }
52         for(int i = 0; i < q; i++) printf("%d\n", ans[i]);
53     }
54     return 0;
55 }

 

posted @ 2018-08-09 09:29  Ctfes  阅读(160)  评论(0编辑  收藏  举报