牛客网2018多校第一场J题
链接:https://www.nowcoder.com/acm/contest/139/J
来源:牛客网
题目描述
Given a sequence of integers a1, a2, ..., an and q pairs of integers (l1, r1), (l2, r2), ..., (lq, rq), find count(l1, r1), count(l2, r2), ..., count(lq, rq) where count(i, j) is the number of different integers among a1, a2, ..., ai, aj, aj + 1, ..., an.
输入描述:
The input consists of several test cases and is terminated by end-of-file.1
The first line of each test cases contains two integers n and q.
The second line contains n integers a
, a2
, ..., an
.i
The i-th of the following q lines contains two integers l
and ri
.
输出描述:
For each test case, print q integers which denote the result.
备注:
* 1 ≤ n, q ≤ 105
i
* 1 ≤ a
≤ ni
* 1 ≤ l
, ri
≤ n
* The number of test cases does not exceed 10.
参考博客https://www.nowcoder.com/discuss/87249
作者:scaufat
链接:https://www.nowcoder.com/discuss/87249
来源:牛客网
首先将原数组扩展为2倍长的,即 a[i+n] = a[i]
对于查询a[1...l]和a[r..n]有多少种不同的数字可以转换为查询 a[r...l+n]有多少种不同的数字
首先考虑维护一个前缀和,pre[i]表示a[1...i]有多少种不同的数字,那么对于a[l...r]的答案就为pre[r] - pre[l-1] + 在a[l...r]和a[1...l-1]同时出现的数字的种类
对于如何求在a[l...r]和a[1...l-1]同时出现的数字的种类,可以考虑使用树状数组维护,树状数组的第i个点表示a[i]是否已经在1...l出现过,对于每个查询只需要查树状数组中l~r的区间和即可
那么我们只要对区间查询进行排序,对于左端每次右移的时候把对应的数的下一个位置加入到数状数组中即可。
1 #include <iostream> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 using namespace std; 6 const int N = 2e5+10; 7 int n,m; 8 int a[N]; 9 int c[N]; 10 int vis[N]; 11 int nex[N]; //记录每个a[i]上一次出现的位置 12 int last[N];//为了记录nex数组所添加的辅助数组用来记录a[i]上一次出现的位置 13 int pre[N]; 14 int answer[N]; 15 struct node 16 { 17 int l,r,id; 18 }querys[N]; 19 int cmp(node x,node y) 20 { 21 return x.l<y.l; 22 } 23 int lowbit(int x) 24 { 25 return x&(-x); 26 } 27 void update(int id,int val) 28 { 29 while(id<=n) 30 { 31 c[id]+=val; 32 id+=lowbit(id); 33 } 34 } 35 int query(int id) 36 { 37 int sum = 0; 38 while(id>0) 39 { 40 sum+=c[id]; 41 id-=lowbit(id); 42 } 43 return sum; 44 } 45 int query(int l,int r) 46 { 47 return query(r) - query(l-1); 48 } 49 int main() 50 { 51 while(scanf("%d%d",&n,&m)!=EOF) 52 { 53 memset(last,-1,sizeof(last)); 54 memset(nex,-1,sizeof(nex)); 55 memset(pre,0,sizeof(pre)); 56 memset(vis,0,sizeof(vis)); 57 memset(a,0,sizeof(a)); 58 memset(c,0,sizeof(c)); 59 memset(answer,0,sizeof(answer)); 60 for(int i = 1; i <= n; i++) 61 { 62 scanf("%d",&a[i]); 63 a[i+n] = a[i]; 64 } 65 n*=2; 66 pre[0] = 0; 67 for(int i = 1; i <= n; i++) 68 { 69 if(!vis[a[i]]) 70 { 71 vis[a[i]] = 1; 72 pre[i] = pre[i-1]+1; 73 } 74 else{ 75 pre[i] = pre[i-1]; 76 } 77 if(~last[a[i]]) 78 { 79 nex[last[a[i]]] = i; 80 } 81 last[a[i]] = i; 82 } 83 for(int i = 0; i < m; i++) 84 { 85 scanf("%d%d",&querys[i].l,&querys[i].r); 86 querys[i].l+=(n/2); 87 swap(querys[i].l,querys[i].r); 88 querys[i].id = i; 89 } 90 sort(querys,querys+m,cmp); 91 int now = 1; 92 for(int i = 0; i < m; i++) 93 { 94 while(now < querys[i].l) 95 { 96 if(~nex[now])//如果当前位置的下一个位置存在,就更新树状数组 97 update(nex[now],1);//更新当前i位置的数a[i]的下一个下一个位置 98 now++; 99 } 100 answer[querys[i].id] = pre[querys[i].r]-pre[querys[i].l-1]+query(querys[i].l,querys[i].r); 101 } 102 for(int i = 0; i < m; i++) 103 printf("%d\n",answer[i]); 104 } 105 return 0; 106 }