欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1878


题意概括

  给出一个长度为n的序列,用m次询问,问区间Li~Ri中有多少种不同的数。

  0<=数值<=1000000,n<=50000,m<=200000


题解

  本题有许多做法。

  这里介绍树状数组和莫队,都是离线算法。

  树状数组

  我们把序列按照R从小到大排序。

  然后从左往右走。

  依次加入数字,当前的状态,比如说搞定了前i个数字。

  对于第i+1个数字,我们要给它做一个标记,但是不可以重复,那么最优的方案就是把它之前的那个位置的+1标记删除,放到这里来。

  于是对于搞定前i个数的时候,有且一定有对于某一个数值,如果它出现过,那么它的+1标记在最后出现的那个地方。

  为什么可以?因为R是递增的!

  然后就是维护一个点修改和区间和的东西了。秒选树状数组。

  莫队

  莫队就是最裸的莫队。

  先把1~n的区间尽量平均的分成sqrt(n)块。

  把所有的询问以L所在的块为第一关键字升序,R为第二关键字升序排序。

  然后就是大暴力。

  朴素的写法有点长。

  但是压缩之后短的无厘头……


代码

  代码1 - 树状数组

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=50000+5,M=200000+5,V=1000000+5;
int n,m,a[N],c[N],pos[V];
struct Query{
int L,R,bh,ans;
bool operator < (const Query x) const {
return R<x.R;
}
}q[M];
bool cmpbh(Query a,Query b){
return a.bh<b.bh;
}
int lowbit(int x){
return x&-x;
}
void add(int x,int d){
if (!x)
return;
for (;x<=n;x+=lowbit(x))
c[x]+=d;
}
int sum(int x){
int ans=0;
for (;x>0;x-=lowbit(x))
ans+=c[x];
return ans;
}
int main(){
scanf("%d",&n);
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].L,&q[i].R);
q[i].bh=i;
}
sort(q+1,q+m+1);
memset(pos,0,sizeof pos);
memset(c,0,sizeof c);
for (int i=1,j=0;i<=m;i++){
while (j<q[i].R){
j++;
add(pos[a[j]],-1);
pos[a[j]]=j;
add(pos[a[j]],1);
}
q[i].ans=sum(q[i].R)-sum(q[i].L-1);
}
sort(q+1,q+m+1,cmpbh);
for (int i=1;i<=m;i++)
printf("%d\n",q[i].ans);
return 0;
}

  代码2 - 莫队

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=50000+5,M=200000+5,V=1000000+5;
int n,m,size,a[N],cnt[V];
struct Query{
int L,R,bh,ans;
}q[M];
bool cmpmd(Query a,Query b){
int k1=a.L/size,k2=b.L/size;
if (k1!=k2)
return k1<k2;
return a.R<b.R;
}
bool cmpbh(Query a,Query b){
return a.bh<b.bh;
}
int main(){
scanf("%d",&n);
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].L,&q[i].R);
q[i].bh=i;
}
size=sqrt(n)+0.5;
memset(cnt,0,sizeof cnt);
sort(q+1,q+m+1,cmpmd);
for (int i=1,tot=0,L=1,R=0;i<=m;i++){
while (R<q[i].R){
R++;
if (cnt[a[R]]==0)
tot++;
cnt[a[R]]++;
}
while (L>q[i].L){
L--;
if (cnt[a[L]]==0)
tot++;
cnt[a[L]]++;
}
while (R>q[i].R){
cnt[a[R]]--;
if (cnt[a[R]]==0)
tot--;
R--;
}
while (L<q[i].L){
cnt[a[L]]--;
if (cnt[a[L]]==0)
tot--;
L++;
}
q[i].ans=tot;
}
sort(q+1,q+m+1,cmpbh);
for (int i=1;i<=m;i++)
printf("%d\n",q[i].ans);
return 0;
}

  代码3 - 莫队+代码压缩

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=50000+5,M=200000+5,V=1000000+5;
int n,m,size,a[N],cnt[V];
struct Query{
int L,R,bh,ans;
}q[M];
bool cmpmd(Query a,Query b){
int k1=a.L/size,k2=b.L/size;
if (k1!=k2)
return k1<k2;
return a.R<b.R;
}
bool cmpbh(Query a,Query b){
return a.bh<b.bh;
}
int main(){
scanf("%d",&n);
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].L,&q[i].R),q[i].bh=i;
size=sqrt(n)+0.5;
memset(cnt,0,sizeof cnt);
sort(q+1,q+m+1,cmpmd);
for (int i=1,tot=0,L=1,R=0;i<=m;i++){
while (R<q[i].R)
tot+=cnt[a[++R]]++==0;
while (L>q[i].L)
tot+=cnt[a[--L]]++==0;
while (R>q[i].R)
tot-=--cnt[a[R--]]==0;
while (L<q[i].L)
tot-=--cnt[a[L++]]==0;
q[i].ans=tot;
}
sort(q+1,q+m+1,cmpbh);
for (int i=1;i<=m;i++)
printf("%d\n",q[i].ans);
return 0;
}

  

BZOJ1878 [SDOI2009]HH的项链 树状数组 或 莫队的更多相关文章

  1. luogu P1972 [SDOI2009]HH的项链 |树状数组 或 莫队

    题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的贝壳,因此,他的项链变得越来越长. ...

  2. [BZOJ1878] [SDOI2009] HH的项链 (树状数组)

    Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变 ...

  3. bzoj1878 [SDOI2009]HH的项链——树状数组

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1878 离线树状数组,巧妙的思路呢: 给每种项链记录一个最后出现的位置lst,根据项链最后出现 ...

  4. BZOJ1878: [SDOI2009]HH的项链[树状数组 离线]

    1878: [SDOI2009]HH的项链 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 3486  Solved: 1738[Submit][Statu ...

  5. BZOJ1878: [SDOI2009]HH的项链[树状数组+离线 | 主席树]

    题意: 询问区间不同种类颜色数 [2016-11-15] 离线好厉害 对于每一个区间询问,一个数只考虑一次,那么考虑他最后出现的一次 将询问按r排序 从1到n扫描,用树状数组维护一个位置应不应该考虑( ...

  6. 【bzoj1878】[SDOI2009]HH的项链 树状数组

    题目描述 HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变得越来越长.有一 ...

  7. 【bzoj1878】[SDOI2009]HH的项链 - 树状数组 - 离线处理

    [SDOI2009]HH的项链 Time Limit: 4 Sec  Memory Limit: 64 MBSubmit: 4834  Solved: 2384[Submit][Status][Dis ...

  8. 【题解】P1972 [SDOI2009]HH的项链 - 树状数组

    P1972 [SDOI2009]HH的项链 声明:本博客所有题解都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。 题目描述 \(HH\) 有一串由各种 ...

  9. bzoj 1878: [SDOI2009]HH的项链 ——树状数组+ 差分

    Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一 段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此他的项链变得 ...

随机推荐

  1. 读取Excel中数据

    #region 读取导入Excel数据 /// <summary> /// /// </summary> /// <param name="filename&q ...

  2. 绘图QPainter-画刷

    Qt提供的画刷风格: Qt.TexturePattern   自定义图像画刷 线性渐变 QLinearGradientPattern QLinearGradient需要传入的参数为需要进行渐变的区域坐 ...

  3. 阿里云3台机器搭建Hadoop HA服务

    1 Mac电脑配置 阿里云配置机器 选择配置 按量付费 选择三台机器  2核8G     

  4. 运维数据库平台~inception测试脚本

    一 简介:今天咱们来聊聊inception的测试脚本 二 范例: #!/usr/bin/python import MySQLdb sql='/*--user=;--password=;--host= ...

  5. git进阶命令

    首先, clone 一个远端仓库,到其目录下: $ Git clone git://example.com/myproject $ cd myproject 然后,看看你本地有什么分支: $ git ...

  6. freeRTOS中文实用教程5--内存管理

    1.前言 不同的嵌入式系统具有不同的内存配置和时间要求.所以单一的内存分配算法只可能适合部分应用程序. FreeRTOS 将内存分配作为可移植层面(相对于基本的内核代码部分而言).这使得不同的应用程序 ...

  7. CentOS6.5运行yum报错:No module named yum

    公司测试机环境不知道给我卸了什么包,导致yum运行报错状况: 报错情况: There was a problem importing one of the Python modulesrequired ...

  8. 详解.NET IL代码(一)

    本文主要介绍IL代码,内容大部分来自网上,进行整理合并的. 一.IL简介 为什么要了解IL代码? 如果想学好.NET,IL是必须的基础,IL代码是.NET运行的基础,当我们对运行结果有异议的时候,可以 ...

  9. Servlet注释与部署描述符

    值得注意的是,部署描述符优先于注释.换句话说,部署描述符覆盖通过注释机制所规定的配置信息.Web 部署描述符的 3.0 版本在 web-app 元素上包含一种名为 metadata-complete ...

  10. Python-互斥锁 进程间通讯

    3.守护进程(**) 主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常: AssertionError: daemonic proces ...