题目:https://www.nowcoder.com/acm/contest/139/J
题意:给出n个数,求 [1,L],[R,n]这两个区间不同数的个数
其实你只要把区间扩大一倍,就是求 [R,L+n]这个区间了

求区间内不同数的个数解决方法有很多

像用离线树状数组、离线莫队、线段树、主席树等等

不过听说主席树会TLE,所以这里主要说一下树状数组和莫队算法
1.树状数组(BIT)
其实可以用树状数组就一定能用线段树,因为树状数组就是从线段树中演变来的,
只不过BIT写起来更方便,其复杂度跟线段树一样,都是 O(log n)
它主要进行区间求和和区间内某个值的加减
现在我们回到题目,求一段区间不同数的个数,做法就是先离线按照R从小到大排序,
然后用map或者一个标记数组,一直只记录每个重复值最后一次出现的下标,用BIT
在这个位置置1,每次更新就-1,一直维护重复值的最后一个的下标+1,然后每次用

BIT去求和就行了

代码如下:

#include<bits/stdc++.h>
using namespace std;
#define MAX 200005
int bit[MAX],n,q;
map<int,int>mp;
struct Query
{int l,r,id;bool operator < (const Query& a)const{return r<a.r;}
}b[MAX];
int gsum(int i)
{int s=0;while(i>0){s+=bit[i];i-=i&-i;}return s;
}
void add(int i,int k)
{while(i<=n){bit[i]+=k;i+=i&-i;}
}
int main()
{while(~scanf("%d %d",&n,&q)){mp.clear();memset(bit,0,sizeof(bit));vector<int>a(n*2+10),ans(q);for(int i=1;i<=n;i++){scanf("%d",&a[i]);a[i+n]=a[i];}n=n*2;for(int i=0;i<q;i++){int l,r;scanf("%d %d",&l,&r);b[i].l=r;b[i].r=l+n/2;b[i].id=i;}sort(b,b+q);int pre=1;for(int i=0;i<q;i++){for(int j=pre;j<=b[i].r;j++){if(mp[a[j]]){add(mp[a[j]],-1);}add(j,1);mp[a[j]]=j;}pre=b[i].r+1;ans[b[i].id]=gsum(b[i].r)-gsum(b[i].l-1);}for(int i=0;i<q;i++){printf("%d\n",ans[i]);}}
}

2、莫队算法

莫队算法这个就是从枚举暴力中优化来的,其复杂度是O(n^1.5);

前提是:如果我们已知[l,r]的答案,能在O(1)时间得到[l+1,r]的答案以及[l,r-1]的答案,

即可使用莫队算法。

给几个链接看看:http://www.cnblogs.com/hzf-sbit/p/4056874.html

http://ydcydcy1.blog.163.com/blog/static/21608904020134411543898/

其中的精华就是分块,用一个block数组将元素分成根号n块,

即:for(int i=1;i<=n;i++)

block[i]=i/sqrt(n);

然后是排序,在本题中就是:

bool cmp(const Query&a,const Query&b)
{
    if(block[a.l]==block[b.l])
        return a.r<b.r;
    else return a.l<b.l;
}

最后就是从[L,R]推出[L,R+1]或者[L+1,R]

完整代码如下:

#include<bits/stdc++.h>
using namespace std;
#define MAX 100005
int block[MAX],ans[MAX],n,b[MAX];
int sum=0;
int read()
{char ch=' ';int ans=0;while(ch>'9'||ch<'0')ch=getchar();while(ch>='0'&&ch<='9'){ans=ans*10+ch-'0';ch=getchar();}return ans;
}
struct Query
{int l,r,id;
}s[MAX];
bool cmp(const Query&a,const Query&b)
{if(block[a.l]==block[b.l])return a.r<b.r;else return a.l<b.l;
}
void inc(int x)
{if(b[x]==0)sum++;b[x]++;
}
void dec(int x)
{b[x]--;if(b[x]==0)sum--;
}
int main()
{int q;while(~scanf("%d %d",&n,&q)){memset(b,0,sizeof(b));vector<int>a(n);for(int i=1;i<=n;i++){a[i]=read();block[i]=i/1000;}for(int i=1;i<=q;i++){s[i].l=read();s[i].r=read();s[i].id=i;}sort(s+1,s+q+1,cmp);int L=0,R=n+1;sum=0;for(int i=1;i<=q;i++){while(L<s[i].l){L++;inc(a[L]);}while(L>s[i].l){dec(a[L]);L--;}while(R<s[i].r){dec(a[R]);R++;}while(R>s[i].r){R--;inc(a[R]);}ans[s[i].id]=sum;}for(int i=1;i<=q;i++)printf("%d\n",ans[i]);}
}

这还是牛客网暑假第一场的签到题…………

转载于:https://www.cnblogs.com/zhgyki/p/9361822.html

求区间不同数的个数 树状数组||莫队算法相关推荐

  1. BZOJ3236[Ahoi2013]作业——莫队+树状数组/莫队+分块

    题目描述 输入 输出 样例输入 3 4 1 2 2 1 2 1 3 1 2 1 1 1 3 1 3 2 3 2 3 样例输出 2 2 1 1 3 2 2 1 提示 N=100000,M=1000000 ...

  2. [蓝桥杯][2016年第七届真题]压缩变换(主席树求区间不同数的个数)

    题目描述 小明最近在研究压缩算法. 他知道,压缩的时候如果能够使得数值很小,就能通过熵编码得到较高的压缩比. 然而,要使数值很小是一个挑战. 最近,小明需要压缩一些正整数的序列,这些序列的特点是,后面 ...

  3. leetcode315. 计算右侧小于当前元素的个数(树状数组解法)

    leetcode315. 计算右侧小于当前元素的个数(树状数组解法) 题目:给定一个整数数组 nums,按要求返回一个新数组 counts.数组 counts 有该性质: counts[i] 的值是 ...

  4. D-query SPOJ - DQUERY(求区间不同数的个数)(树状数组||线段树+离散)(主席树+在线)

    English Vietnamese Given a sequence of n numbers a1, a2, -, an and a number of d-queries. A d-query ...

  5. 区间素数个数 树状数组 HIT 1867 经理的烦恼

    http://acm.hit.edu.cn/hoj/problem/view?id=1867 经理的烦恼   Source : HCPC 2005 Spring   Time limit : 2 se ...

  6. 二维树状数组 ----2021广东省赛 ----- K - Kera‘s line segment[区间转二维平面+树状数组维护前缀最小最大值]

    题目链接 题目大意: 就是一个一维的数轴上面有一堆线段用一个三元组(l,r,val)(l,r,val)(l,r,val)表示. 现在我们有两个操作: 就是往数轴上面添加线段 询问[L,R][L,R][ ...

  7. 动态区间第k小:树状数组套权值线段树

    所谓树状数组套权值线段树,就是在树状树组上套权值线段树 (逃) 解析 如何解决静态区间第k小? 使用主席树就ok啦 辣么如何解决动态区间第k小嘞- 我们想想主席树为啥不能解决动态区间第k小 因为如果改 ...

  8. C++数星星(树状数组)

    天空中有一些星星,这些星星都在不同的位置,每个星星有个坐标. 如果一个星星的左下方(包含正左和正下)有 k 颗星星,就说这颗星星是 k级的. 例如,上图中星星 是 3 级的(1,2,4 在它左下),星 ...

  9. python 树状数组_【算法日积月累】19-高级数据结构:树状数组

    树状数组能解决的问题 树状数组,也称作"二叉索引树"(Binary Indexed Tree)或 Fenwick 树. 它可以高效地实现如下两个操作: 1.数组前缀和的查询: 2. ...

  10. SPOJ 3267: DQUERY 树状数组,离线算法

    给出q个询问,询问一段区间里面的不同元素的个数有多少个. 离线做,用树状数组. 设树状数组的意义是:1--pos这个段区间的不用元素的种类数.怎么做?就是add(pos,1);在这个位置中+1,就是说 ...

最新文章

  1. wordpressPHP实现ajax评论,wordpress无刷新评论:无需插件ajax实现wordpress comment无刷新机制...
  2. spring事务介绍
  3. MySQL、Oracle、SQL Server
  4. 8086实时时钟实验(二)——《x86汇编语言:从实模式到保护模式》读书笔记06
  5. vue 固定div 滚动_vue移动端 导航吸顶(固定定位)页面滚动出现抖动
  6. linux下工具exfs用法
  7. python中的封装调用_Python基础之封装
  8. docker如何部署python项目_Docker如何部署Python项目的实现详解
  9. arm中断保护和恢复_浅谈ARM处理器的七种异常处理
  10. Asp.Net Forums研究文章集合(收藏)
  11. SAP License:你是怎么理解ERP的?
  12. 同济版《线性代数》引发激烈争议!
  13. 智能泊车技术及现状详解
  14. ps切图教程 android,PS前端切图完整教程
  15. 我的世界服务器皮肤文件夹在哪里,我的世界青龙皮肤文件,启动侠皮肤文件夹在哪个文件夹...
  16. BatchFormer: Learning to Explore Sample Relationships for Robust Representation Learning
  17. ERP中英文缩写汇总
  18. 30000字Linux期末考试复习总结
  19. 使用Velocity导出Word文档
  20. python报错No module named XXX解决方法

热门文章

  1. 苹果mac微软windows远程连接工具:microsoft remote desktop
  2. Java代码动态分析JProfiler 13 for Mac
  3. Patternodes 3 for Mac(创建图形矢量模式工具)
  4. Astute Graphics for Mac(ai创意插件合集)
  5. 升级macOS Big Sur 无法开机/死机怎么办?
  6. Android系统的开机画面显示过程分析(12)
  7. (转)Scala中协变(+)、逆变(-)、上界(:)、下界(:)简单介绍
  8. android selector 开始自定义样式
  9. 存储单位--MBR-GPT
  10. Spring声明式事务管理示例——MyBatis学习笔记之十六