BZOJ1878 [SDOI2009]HH的项链 树状数组 或 莫队
欢迎访问~原文出处——博客园-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的项链 树状数组 或 莫队的更多相关文章
- luogu P1972 [SDOI2009]HH的项链 |树状数组 或 莫队
题目描述 HH 有一串由各种漂亮的贝壳组成的项链.HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH 不断地收集新的贝壳,因此,他的项链变得越来越长. ...
- [BZOJ1878] [SDOI2009] HH的项链 (树状数组)
Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变 ...
- bzoj1878 [SDOI2009]HH的项链——树状数组
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1878 离线树状数组,巧妙的思路呢: 给每种项链记录一个最后出现的位置lst,根据项链最后出现 ...
- BZOJ1878: [SDOI2009]HH的项链[树状数组 离线]
1878: [SDOI2009]HH的项链 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 3486 Solved: 1738[Submit][Statu ...
- BZOJ1878: [SDOI2009]HH的项链[树状数组+离线 | 主席树]
题意: 询问区间不同种类颜色数 [2016-11-15] 离线好厉害 对于每一个区间询问,一个数只考虑一次,那么考虑他最后出现的一次 将询问按r排序 从1到n扫描,用树状数组维护一个位置应不应该考虑( ...
- 【bzoj1878】[SDOI2009]HH的项链 树状数组
题目描述 HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此, 他的项链变得越来越长.有一 ...
- 【bzoj1878】[SDOI2009]HH的项链 - 树状数组 - 离线处理
[SDOI2009]HH的项链 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 4834 Solved: 2384[Submit][Status][Dis ...
- 【题解】P1972 [SDOI2009]HH的项链 - 树状数组
P1972 [SDOI2009]HH的项链 声明:本博客所有题解都参照了网络资料或其他博客,仅为博主想加深理解而写,如有疑问欢迎与博主讨论✧。٩(ˊᗜˋ)و✧*。 题目描述 \(HH\) 有一串由各种 ...
- bzoj 1878: [SDOI2009]HH的项链 ——树状数组+ 差分
Description HH有一串由各种漂亮的贝壳组成的项链.HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一 段贝壳,思考它们所表达的含义.HH不断地收集新的贝壳,因此他的项链变得 ...
随机推荐
- resultMap自定义某个javaBean的封装规则代码
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "- ...
- Hadop 基础
HDFS 体系结构 mapreduce 体系结构和算法 haddop 集群 zookeeper 操作:HBase 体系结构Hive /Sqoop 体系结构和基本操作: mapreduce 逻辑处理数据 ...
- 字体选择框QFontComboBox
self.combobox_2 = QFontComboBox(self) # 实例化字体列表框 combobox.currentFont() 返回字体选择框中当前的字体 self.combobo ...
- POJ 1200 Crazy Search (哈希)
题目链接 Description Many people like to solve hard puzzles some of which may lead them to madness. One ...
- DSO windowed optimization 代码 (1)
这里不想解释怎么 marginalize,什么是 First-Estimates Jacobian (FEJ).这里只看看代码,看看Hessian矩阵是怎么构造出来的. 1 优化流程 整个优化过程,也 ...
- Linux时间日期类指令
⒈date [Options] 显示/设置当前日期 基本语法: date 显示当前时间 date +"%Y" 显示当前年份 date +"%m" 显示当前月份 ...
- 恶意PDF文档分析记录
0x1 PDF是什么 PDF(便携式文件格式,Portable Document Format)是由Adobe Systems在1993年用於文件交换所发展出的文件格式. 因为PDF的文件格式性质广泛 ...
- was监控脚本编写时的注意点
server = AdminConfig.getid('/Cell:myCell012/Node:myNode12/Server:server1/') 不可缺少斜杠,不然会报错 如果没法登录管理控制台 ...
- TortoiseSVN常用配置
在Windows下推荐使用乌龟(Tortoise)SVN客户端. TortoiseSVN 是 Subversion 版本控制系统的一个免费开源客户端,可以超越时间的管理文件和目录. 文件保存在中央版本 ...
- 深入解析内存原理:SRAM的基本原理
1. SRAM芯片的引脚定义早期的SRAM 芯片采用了20 线双列直插(DIP:Dual Inline Package)封装技术,它们之所以具有这么多的针脚,是因为它们必须:• 每个地址信号都需要一根 ...