[bzoj] 1878 HH的项链 || 莫队

原题

给定长为 n 的一个序列,接下来 m 次询问,每次询问区间 [ l , r ] 内有多少个不同的数。


莫队:
离线\(O(n\log(n))\)
将序列分块。
以左端点所在块为第一关键字,右端点位置为第二关键字sort,然后two-points移动暴力记录即可。

#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 50010
#define M 200010
using namespace std;
int n,m,ans[M],tot,a[N],cnt[1000010],s,l,r;

int bel(int x) { return ((x-1)/s+1); }

struct hhh
{
    int x,y,id;
    bool operator < (const hhh &b) const
	{
	    if (bel(x)==bel(b.x)) return y<b.y;
	    return bel(x)<bel(b.x);
	}
}q[M];

int read()
{
    int ans=0,fu=1;
    char j=getchar();
    for (;j<'0' || j>'9';j=getchar()) if (j=='-') fu=-1;
    for (;j>='0' && j<='9';j=getchar()) ans*=10,ans+=j-'0';
    return ans*fu;
}

int main()
{
    n=read();s=sqrt(n);
    for (int i=1;i<=n;i++)
	a[i]=read();
    m=read();
    for (int i=1;i<=m;i++) q[i].x=read(),q[i].y=read(),q[i].id=i;
    sort(q+1,q+m+1);
    for (int i=1;i<=m;i++)
    {
	while (l<q[i].x) if (!--cnt[a[l++]]) tot--;
	while (l>q[i].x) if (!cnt[a[--l]]++) ++tot;
	while (r<q[i].y) if (!cnt[a[++r]]++) ++tot;
	while (r>q[i].y) if (!--cnt[a[r--]]) tot--;
	ans[q[i].id]=tot;
    }
    for (int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}
posted @ 2018-01-04 09:48  Mrha  阅读(98)  评论(0编辑  收藏  举报