D-query SPOJ 树状数组+离线/莫队算法

题意

有一串正数,求一定区间中有多少个不同的数

解题思路——树状数组

说明一下,树状数组开始全部是零。

首先,我们存下所有需要查询的区间,然后根据右端点进行从小到大的排序。然后依次处理这个区间中的答案,仔细想一下,后面的区间答案不会受到影响。

怎么处理区间中的答案呢?

我们按照数字出现的顺序,向树状数组中加一,如果这个数字之前出现了,那么需要树状数组在这个数字上次出现的位置减一,这样可以保证在一定区间内,每个数字都有在树状数组中唯一对应的1,当处理到数字的位置到达某个询问的右端点时,就可以求一下这个询问区间有几个1,这个就是这个区间内不同数字的个数。

这里需要标记数字是否之前出现过,因此就开了一个vis数组,但是题目数字出现的范围太大而输入的数字个数不是很多,因此可以进行离散化,重新进行映射到小的区间中。当然也可以使用map。

点操作+区间求和正好就可以使用树状数组。

下面是代码实现,有注释可以更加清晰。

莫队算法

莫队算法看了好多博客文章,这个题是入门题,思想很巧妙,复杂度在\(O(n*lgn)\)

详解这里就不写了,主要是最近时间比较紧,得赶紧看其他题,这里就推荐一个博客,写的很好,就是背景太花哨了,影响到我阅读。传送门

代码实现(树状数组+莫队算法)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
using namespace std;
typedef long long ll;
const int maxn=3e4+7;
const int maxq=2e5+7;
struct query{
int L, R, id;
bool friend operator <(query a, query b)
{
return a.R < b.R;
}
}q[maxq];
int num[maxn]; //存储那一串数字
int bak[maxn]; //备份数字,用来进行离散化
int sum[maxn]; //树状数组
int pre[maxn]; //记录数字之前出现的位置
int vis[maxn]; //标记数字是否出现过
int ans[maxq]; //离线处理,需要记录答案,之后一并输出
int n, m, cnt; //n数字的个数,m个询问,cnt是映射后的范围
void up(int id, int x)
{
while(id<=n)
{
sum[id]+=x;
id += id&(-id);
}
} ll getsum(int id)
{
ll ret=0;
while(id>0)
{
ret+=sum[id];
id -= id&(-id);
}
return ret;
}
int getid(int num) //求映射后的编码
{
return lower_bound(bak, bak+cnt, num)-bak+1;
}
int main()
{
while(scanf("%d", &n)!=EOF)
{
for(int i=1;i<=n; i++) //初始化
{
sum[i]=0;
vis[i]=0;
}
for(int i=1; i<=n; i++) //读入数据+备份。
{
scanf("%d", &num[i]);
bak[i-1]=num[i];//从0开始便于后面初始化
}
scanf("%d", &m);
for(int i=1; i<=m; i++)//读入查询
{
scanf("%d%d", &q[i].L, &q[i].R);
q[i].id=i;
}
sort(q+1, q+m+1);//排序
sort(bak, bak+n);//离散化先排序
cnt=unique(bak, bak+n)-bak;//去重后的个数
int j=1;
for(int i=1; i<=m; i++)
{
while(j <= q[i].R && j<=n)
{
int tmp=getid(num[j]); //获取编号
if(vis[tmp]!=0)
{
up(pre[tmp], -1);
pre[tmp]=j;
up(j, 1);
j++;
}
else {
pre[tmp]=j;
vis[tmp]=1;
up(j, 1);
j++;
}
}
ans[q[i].id]=getsum(q[i].R)-getsum(q[i].L-1);
}
for(int i=1; i<=m; i++)
{
printf("%d\n", ans[i]);
}
}
return 0;
}
//莫队算法
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=3e4+7;
const int maxq=2e5+7;
int a[maxn];
int book[1000007]; //记录是否出现和出现的次数
int ans[maxq];
int block, tmp;
struct node{
int s, t;
int id, blk;
bool friend operator < (node a, node b)
{
if(a.blk==b.blk)
return a.t < b.t;
return a.s<b.s;
}
}q[maxq];
void add(int x)
{
if(book[a[x]]==0)
tmp++;
book[a[x]]++;
}
void del(int x)
{
book[a[x]]--;
if(book[a[x]]==0)
tmp--;
}
int main()
{
int n, m;
while(scanf("%d", &n)!=EOF)
{
memset(book, 0, sizeof(book));
block=sqrt(n*1.0);
for(int i=1; i<=n; i++)
{
scanf("%d", &a[i]);
}
scanf("%d", &m);
for(int i=1; i<=m; i++)
{
scanf("%d%d", &q[i].s, &q[i].t);
q[i].id=i;
q[i].blk=q[i].s/block;
}
sort(q+1, q+m+1);
int l=1, r=0, s, t;
tmp=0;
for(int i=1; i<=m; i++)
{
s=q[i].s;
t=q[i].t;
while(l<s)
{
del(l);
l++;
}
while(l>s)
{
l--;
add(l);
}
while(r<t)
{
r++;
add(r);
}
while(r>t)
{
del(r);
r--;
}
ans[q[i].id]=tmp;
}
for(int i=1; i<=m; i++)
{
printf("%d\n", ans[i]);
}
}
return 0;
}

D-query SPOJ 树状数组+离线的更多相关文章

  1. SPOJ DQUERY树状数组离线or主席树

    D-query Time Limit: 227MS   Memory Limit: 1572864KB   64bit IO Format: %lld & %llu Submit Status ...

  2. Necklace HDU - 3874 (线段树/树状数组 + 离线处理)

    Necklace HDU - 3874  Mery has a beautiful necklace. The necklace is made up of N magic balls. Each b ...

  3. 2016 Multi-University Training Contest 5 1012 World is Exploding 树状数组+离线化

    http://acm.hdu.edu.cn/showproblem.php?pid=5792 1012 World is Exploding 题意:选四个数,满足a<b and A[a]< ...

  4. HDU 5869 Different GCD Subarray Query 树状数组+离线

    Problem Description This is a simple problem. The teacher gives Bob a list of problems about GCD (Gr ...

  5. HDU3333 Turing Tree 树状数组+离线处理

    Turing Tree Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total ...

  6. HDU 4417 - Super Mario ( 划分树+二分 / 树状数组+离线处理+离散化)

    题意:给一个数组,每次询问输出在区间[L,R]之间小于H的数字的个数. 此题可以使用划分树在线解决. 划分树可以快速查询区间第K小个数字.逆向思考,判断小于H的最大的一个数字是区间第几小数,即是答案. ...

  7. Codeforces Round #365 (Div. 2) D 树状数组+离线处理

    D. Mishka and Interesting sum time limit per test 3.5 seconds memory limit per test 256 megabytes in ...

  8. HDU 4630 No Pain No Game 树状数组+离线查询

    思路参考 这里. #include <cstdio> #include <cstring> #include <cstdlib> #include <algo ...

  9. HDOJ 4417 - Super Mario 线段树or树状数组离线处理..

    题意: 同上 题解: 抓着这题作死的搞~~是因为今天练习赛的一道题.SPOJ KQUERY.直到我用最后一种树状数组通过了HDOJ这题后..交SPOJ的才没超时..看排名...时间能排到11名了..有 ...

随机推荐

  1. Apache HttpClient 读取响应乱码问题总结

    Apache HttpClient 读取响应乱码问题总结 setCharacterEncoding  Content-Type  HttpClient  起因 最近公司产品线研发人员调整,集中兵力做战 ...

  2. Jackson常用工具类

    原创转载请注明出处:https://www.cnblogs.com/agilestyle/p/11983194.html Demo package org.fool.util; import com. ...

  3. 对redis高并发测试的研究

    以下引用大神的: 测试项目: https://github.com/14251104246/redis-demo.git 准备 使用docker-compose命令启动redis服务器(可以用其他方式 ...

  4. 认识js数组

    1.认识数组 数组就是某类数据的集合,数据类型可以是整型.字符串.甚至是对象Javascript不支持多维数组,但是因为数组里面可以包含对象(数组也是一个对象),所以数组可以通过相互嵌套实现类似多维数 ...

  5. 【bzoj2502】清理雪道

    题目描述: 滑雪场坐落在FJ省西北部的若干座山上. 从空中鸟瞰,滑雪场可以看作一个有向无环图,每条弧代表一个斜坡(即雪道),弧的方向代表斜坡下降的方向. 你的团队负责每周定时清理雪道.你们拥有一架直升 ...

  6. Linux 安装R包

    https://www.cnblogs.com/jessepeng/p/10984983.html Linux 的R环境,可以通过anaconda jupyter notbook很容易的配置,见我之前 ...

  7. 【BZOJ2460】元素(拟阵)

    题意:给定n个物品,每个物品有属性x和价值y,要求从中选出一些使得价值和最大并且其中没有属性xor和为0的非空子集 n<=1000,x<=1e18,y<=1e4 思路:没有xor和为 ...

  8. 学习日记17,、、通过反射获取model实体属性display的值

    本来是想到网上直接找个用的,但是找的一些都不是我想要的,然后就参考自己摸索写了一个 这里的UserModel是我自己定义的一个实体类,代码就不用放出来了 var t = typeof(UserMode ...

  9. [CSP-S模拟测试]:导弹袭击(数学+凸包+单调栈)

    题目背景 $Guess$准备向敌军阵地发起进攻了!$Guess$的武器是自动制导导弹.然而在机房是不允许游戏的,所以班长$XZY$对游戏界面进行了降维打击,结果... 题目描述 众所周知,环境因素对导 ...

  10. Qualcomm 8X camera过程解析【转】

    本文转载自:http://blog.csdn.net/gabbzang/article/details/19906687 http://www.01yun.com/mobile_development ...