折腾了一大半天,咳咳咳。终于搞定了莫队算法的模板。
(被那些鬼畜的细节整的)亏班上还在黑板上方还挂着巨大的细节决定成败的牌子
大意
这道题目的意思是给出一个长度为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)