【BZOJ1878】【codevs2307】HH的项链,莫队算法

传送门1
传送门2
写在前面:信息课上的莫队练习
思路:比小Z的袜子还要简单些,不过BZOJ上4s的总时限确实把我吓了一跳
注意:种类编号为0-1000000,小心数组越界导致RE
代码:

#include"bits/stdc++.h"
using namespace std;
int m,n,tot,last_l=1,last_r;
int a[50010],block[50010],flag[1000001];
struct os
{
    int l,r,num,ans;
}q[200010];
int cmp1(os x,os y)
{
    if (block[x.l]<block[y.l]) return 1;
    if (block[x.l]>block[y.l]) return 0;
    return x.r<y.r;
}
int cmp2(os x,os y){return x.num<y.num;}
int in()
{
    int f=1,t=0;
    char ch=getchar();
    while (ch>'9'||ch<'0')
    {
        if (ch=='-') f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9') t=t*10+ch-'0',ch=getchar();
    return f*t;
}
main()
{
    n=in();
    for (int i=1;i<=n;i++) a[i]=in();
    block[0]=sqrt(n);
    for (int i=1;i<=n;i++)
    block[i]=(i-1)/block[0]+1;
    m=in();
    for (int i=1;i<=m;i++)
    q[i].l=in(),
    q[i].r=in(),
    q[i].num=i;
    sort(q+1,q+m+1,cmp1);
    for (int i=1;i<=m;i++)
    {
        if (q[i].r>last_r)
        for (int j=last_r+1;j<=q[i].r;j++)
        {
            if (!flag[a[j]]) tot++;
            flag[a[j]]++;
        }
        if (q[i].r<last_r)
        for (int j=last_r;j>q[i].r;j--)
        {
            flag[a[j]]--;
            if (!flag[a[j]]) tot--;
        }
        if (q[i].l<last_l)
        for (int j=last_l-1;j>=q[i].l;j--)
        {
            if (!flag[a[j]]) tot++;
            flag[a[j]]++;
        }
        if (q[i].l>last_l)
        for (int j=last_l;j<q[i].l;j++)
        {
            flag[a[j]]--;
            if (!flag[a[j]]) tot--;
        }
        last_l=q[i].l;
        last_r=q[i].r;
        q[i].ans=tot;
    }
    sort(q+1,q+m+1,cmp2);
    for (int i=1;i<=m;i++) printf("%d\n",q[i].ans);
}

你可能感兴趣的:(【BZOJ1878】【codevs2307】HH的项链,莫队算法)