洛谷 P1972 [SDOI2009]HH的项链

折腾了一大半天,咳咳咳。终于搞定了莫队算法的模板。

(被那些鬼畜的细节整的)亏班上还在黑板上方还挂着巨大的细节决定成败的牌子

题目直通车

大意

这道题目的意思是给出一个长度为n的序列s,再给出m个询问,对于每一个询问的x,y,要求求出在s[x]--s[y]的数的种类。

算法

蒟蒻不会什么算法,只能打暴力了。但普通的暴力会炸,我们得把它写得优美一点,那就是用莫涛大大大神的莫队算法。一种能够在较普通算法高效,并且能让我(一个没有理科思维的理科生)较快理解的算法。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <algorithm>
using namespace std;
struct Query
{
    int x,y,num,vl;
};
    Query q[211111];
    int bl,a[51111],n,m,b[1001111];
int cmp(Query x,Query y)
{    
        return ((x.x/bl)!=(y.x/bl))?(x.x<y.x):(x.y<y.y); 
}  
int cpm(Query a,Query b)
{
    return a.num<b.num;
}
int main(int argc, char **argv)
{
    int i,j;
    scanf("%d",&n);
    bl=sqrt(n);
        for(i=1;i<=n;++i)
            scanf("%d",&a[i]);
        scanf("%d",&m);
        for(i=1;i<=m;++i)
            scanf("%d%d",&q[i].x,&q[i].y),q[i].num=i;
        sort(q+1,q+1+m,cmp);//莫队算法优化核心
        memset(b,0,sizeof(b));    
    for(i=q[1].x;i<=q[1].y;++i)
        {
            if(b[a[i]]==0) ++q[1].vl;
            ++b[a[i]];
        }
    for(i=2;i<=m;++i)
        {
            q[i].vl=q[i-1].vl;
            if(q[i].x<q[i-1].x)
                for(j=q[i].x;j<q[i-1].x;++j)
                {
                    if(b[a[j]]==0) ++q[i].vl;
                    ++b[a[j]];
                }
            if(q[i].y>q[i-1].y)
                for(j=q[i-1].y+1;j<=q[i].y;++j)
                {
                    if(b[a[j]]==0) ++q[i].vl;
                    ++b[a[j]];
                }
            if(q[i].x>q[i-1].x)
                for(j=q[i].x-1;j>=q[i-1].x;--j)
                {
                    if(b[a[j]]==1) --q[i].vl;
                    --b[a[j]];
                }
            if(q[i].y<q[i-1].y)
                for(j=q[i-1].y;j>q[i].y;--j)
                {
                    if(b[a[j]]==1) --q[i].vl;
                    --b[a[j]];
                }
        }
        sort(q+1,q+1+m,cpm);
        for(i=1;i<=m;++i)
            printf("%d\n",q[i].vl);
    return 0;
}
注:本人亦在洛谷博客发布了此代码。

本文章写于Ubuntu 17.10平台(Chrome 64)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值