当前位置:   article > 正文

2018牛客网暑假多校第一场J(树状数组+思维)_成熟的阿梓发现了一种构造成熟的数列的方法 假设该数列叫 a,给定这个数列的前两项

成熟的阿梓发现了一种构造成熟的数列的方法 假设该数列叫 a,给定这个数列的前两项

题目描述:

    有一个n个数的数列,并由q个询问,每一个询问有一个l和r,问你在区间a1—al和ar—an这两个区间中有多少个不同的数。

题目分析:

    这个题目事实上是spoj的某一题的改编,原题是求l到r区间有多少个不同的数,现在这个题是要求两个分开的区间有多少个不同的数。

    事实上这个题的做法跟求l到r区间有多少个不同的数的做法相类似。首先,因为数据范围很大,因此我们需要进行离线的操作。离线操作我们可以用莫队甚至主席树进行操作。但是这个题我们可以用树状数组进行维护。首先我们先将询问数组以有端点从小到大进行排序,之后,倘若该数为出现过,则在这位上置1;反之,倘若该数未出现过,则利用差分的思想在之前那一位置-1。

    到上面为止,这就是求l到r区间内不同的数的做法。但是在这道题来说,我们要求的是两个独立的区间。因此我们就需要发挥我们的脑洞,我们可以倍增整个数列的大小,此时对于左半个区间,倘若我们将左区间+n,右区间不变,那么我们就将原来两个不相交的区间变为了一个连续的区间。此时,我们就可以用上诉的方法求一段连续的区间的不同的数的个数。

代码:

  1. #include <bits/stdc++.h>
  2. #define maxn 100005*2
  3. using namespace std;
  4. int a[maxn];
  5. int bit[maxn];//树状数组
  6. int vis[maxn];
  7. int sum[maxn];
  8. unsigned int read()//读入挂
  9. {
  10. unsigned int ret=0;
  11. char ch=getchar();
  12. while(ch>'9'||ch<'0')ch=getchar();
  13. while(ch>='0'&&ch<='9')
  14. {
  15. ret=ret*10+ch-'0';
  16. ch=getchar();
  17. }
  18. return ret;
  19. }
  20. struct node{
  21. int l,r,id;
  22. bool operator <(const node & w)const{//按照右端点排序
  23. return r<w.r;
  24. }
  25. }q[maxn];
  26. int lowbit(int x){
  27. return x&(-x);
  28. }
  29. void add(int x,int d){
  30. while(x<maxn){
  31. bit[x]+=d;
  32. x+=lowbit(x);
  33. }
  34. return;
  35. }
  36. int get_sum(int x){
  37. int res=0;
  38. while(x){
  39. res+=bit[x];
  40. x-=lowbit(x);
  41. }
  42. return res;
  43. }
  44. int main()
  45. {
  46. int n,Q;
  47. while(~scanf("%d%d",&n,&Q)){
  48. memset(bit,0,sizeof(bit));
  49. memset(vis,0,sizeof(vis));
  50. for(int i=1;i<=n;i++){
  51. //scanf("%d",&a[i]);
  52. a[i]=read();
  53. }
  54. for(int i=1;i<=n;i++) a[i+n]=a[i];//建立倍增数组
  55. for(int i=1;i<=Q;i++){
  56. int tmp=read();
  57. q[i].r=tmp+n;//此时询问的右端点为原来的左端点+n
  58. q[i].l=read();//此时询问的左端点为原来右端点
  59. //scanf("%d%d",&q[i].l,&q[i].r);
  60. q[i].id=i;
  61. }
  62. sort(q+1,q+1+Q);
  63. int cur=1;
  64. for(int i=1;i<=2*n&&cur<=Q;i++){
  65. if(vis[a[i]]){
  66. add(vis[a[i]],-1);//出现过,则在前一位置-1
  67. }
  68. vis[a[i]]=i;
  69. add(vis[a[i]],1);//在该位置1
  70. while(cur<=Q&&q[cur].r<=i){
  71. sum[q[cur].id]=get_sum(q[cur].r)-get_sum(q[cur].l-1);
  72. cur++;
  73. }
  74. }
  75. for(int i=1;i<=Q;i++){
  76. printf("%d\n",sum[i]);
  77. }
  78. }
  79. }

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/986506
推荐阅读
相关标签
  

闽ICP备14008679号