洛谷Oj-P1972 [SDOI2009]HH的项链-莫队

3人阅读 评论(0) 收藏 举报

问题描述:
HH 有一串由各种漂亮的贝壳组成的项链。HH 相信不同的贝壳会带来好运,所以每次散步完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH 不断地收集新的贝壳,因此,他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答……因为项链实在是太长了。于是,他只好求助睿智的你,来解决这个问题。
AC代码:

struct query//一个查询
{
    int l;//左端点
    int r;/右端点
    int id;//第id个查询
    int b;//在第b个块中
    int ans;//答案
};
query q[200010];
int a[500000];//原数组
int cnt[1000010];//记录数字出现的次数
int curL,curR;//指针
int k;//当前区间内数字的种类数
bool cmp1(const query &a,const query &b)
{
    if(a.b == b.b)
        return a.r < b.r;//块内按右端点排序
    return a.b < b.b;//块间排序
}
bool cmp2(const query &a,const query &b)//恢复初始的查询顺序
{
    return a.id < b.id;
}
void add(int id)//将a[id]加入当前区间
{
    cnt[a[id]]++;//计数+1
    if(cnt[a[id]] == 1)//如果为1,说明是第一次出现
        k++;
    return;
}
void del(int id)//将a[id]从当前区间删除
{
    cnt[a[id]]--;//计数-1
    if(cnt[a[id]] == 0)//如果为0,说明区间内已无此数
        k--;
    return;
}
inline void solve(query &q)//莫队算法的核心,注意需要引用
{
    //l、r为当前的查询
    int l = q.l;
    int r = q.r;
    while(curL < l)//如果当前左指针在l的左边,cur == l时退出循环
    {
        del(curL);//先将所指元素出现的次数-1
        curL++;//再移动指针
    }
    while(curL > l)//如果当前左指针在l的右边,cur == l时退出循环
    {
        curL--;//先移动指针
        add(curL);//再将所指元素出现的次数+1
    }
    while(curR < r)//同上,注意自增自减的顺序
    {
        curR++;
        add(curR);
    }
    while(curR > r)//同上
    {
        del(curR);
        curR--;
    }
    q.ans = k;
}
int main()
{
    int n;
    cin >> n;
    int sz = sqrt(n);//块的大小
    for(int i = 1; i <= n; ++i)
        scanf("%d",&a[i]);
    int m;
    cin >> m;
    for(int i = 1; i <= m; ++i)//处理每一个查询
    {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].b = q[i].l / sz;//块的编号
        q[i].id = i;
    }
    sort(q + 1,q + m + 1,cmp1);
    //初始化左右指针
    curL = 1;
    curR = 0;
    for(int i = 1; i <= m; ++i)
        solve(q[i]);//求解
    sort(q + 1,q + m + 1,cmp2);
    for(int i = 1; i <= m; ++i)//输出
        cout << q[i].ans << endl;
    return 0;
}

解决方法:
这道题是一道经典的莫队题,如果暴力地去做的话,之前获得的信息没有被利用,造成了浪费,时间开销就大。如果将这若干个查询进行处理,使得我们能较好的利用上一次求解获得的信息,那么复杂度就会得到改善。
对这些查询进行离线处理,根据查询的左端点进行排序,分成若干个块,每个块内则按照查询的右端点由小到大进行排序,这样就避免了指针前前后后乱跑,从而节省了时间
cnt数组与k配合地不错
如果数据的值比较大,而个数比较少,则考虑对其进行离散化

查看评论

Android项目_硅谷p2p金融(一)

硅谷p2p金融项目,结合现有第三方应用市场上主流p2p金融理财产品特点,集成了新的技术与框架。该项目内容包含p2p金融理财业务流程,数据加密、解密,客户端异常信息上传,用户登录注册,数据的图表展示,第三方支付,手势密码,分享功能等。
  • 2017年02月10日 09:48

洛谷 P1972 [SDOI2009]HH的项链

莫队算法
  • chai_jing
  • chai_jing
  • 2016-09-05 18:17:25
  • 327

洛谷P1972:[SDOI2009]HH的项链(莫队/线段树)

题目传送门:https://www.luogu.org/problem/show?pid=1972 分析:本题有很多种做法,有O(n*log(n))的线段树,也有O(n*sqrt(n))的莫队。线段树...
  • KsCla
  • KsCla
  • 2017-04-18 13:41:55
  • 455

BZOJ1878: [SDOI2009]HH的项链(莫队)

传送门 题意 给你一个数列,询问(l,r)中不同种类的数的个数。 题解 很经典的莫队算法,这道题可以说是板题了。所谓莫队就是将询问排序,这次的询问部分信息与上次询问一致,来尽量压缩时间,对于一次询问(...
  • qq_35649707
  • qq_35649707
  • 2017-07-14 21:29:55
  • 139

[BZOJ]1878: [SDOI2009]HH的项链 莫队算法

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

1878: [SDOI2009]HH的项链

看见题目第一眼就想到莫队了,为什么看网上一堆题解都是树状数组,果然我智商低吗QAQ。 算了,反正莫队乱搞就好了。 很明显,我们用一个数组记录编号为i的贝壳有多少个,增减的时候处理一下维护答案,即在...
  • nlj1999
  • nlj1999
  • 2015-12-14 15:59:37
  • 221

【bzoj1878】[SDOI2009]HH的项链

莫队裸题。#include #define rep(i,a,b) for(int i=a,_=b;i=_;i--) #define maxn 50007 #define maxm 200007inl...
  • GEOTCBRL
  • GEOTCBRL
  • 2015-11-20 23:45:18
  • 744

【主席树|莫队|离线树状数组】BZOJ1878 [SDOI 2009]HH的项链

题面在这里这道题有三种解法,以下分别介绍(等我A掉会补全)【主席树】关于主席树戳这里造一个lst[i]表示位置i的这个数上一次出现的位置(如果没有就是0) 那么对于每次询问L~R范围里的数字种数 ...
  • linkfqy
  • linkfqy
  • 2017-04-25 07:18:18
  • 829

BZOJ_P1878&Codevs_P2307 [SDOI2009]HH的项链(莫队算法)

BZOJ传送门 Codevs传送门 Time Limit: 4 Sec Memory Limit: 64 MB Submit: 2643 Solved: 1323 [Submit][Sta...
  • qq_18455665
  • qq_18455665
  • 2016-02-24 17:51:13
  • 289

线段树/莫队——BZOJ1878/Luogu1972 [SDOI2009]HH的项链

http://www.lydsy.com/JudgeOnline/problem.php?id=1878 https://www.luogu.org/problem/show?pid=1972 隔...
  • jzq233jzq
  • jzq233jzq
  • 2017-04-11 08:19:35
  • 138
    个人资料
    持之以恒
    等级:
    访问量: 2万+
    积分: 2362
    排名: 1万+
    最新评论