BZOJ 1878 SDOI2009 HH的项链 / SPOJ D-query (莫队算法)

题意:询问你L到R区间右多少种数;

思路:在线应该是可以用主席数树处理的,听说离线的话梳妆数组也可以(不怎么会树状数组这种操作),这里给出的是离线处理的莫队算法(网上好像很多事用一个增加函数,和一个减小函数进行操作的,这里只写了一个函数,偷懒了),莫队的话我觉得hzw学长的博客写的(小z的袜子)比较好,打波广告

代码:(这是SPOJ的代码,BZOJ的代码和这个类似,只是注意数据范围,不然会一直RE)

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int N=3e5+7;
int block,cnt[1000007],a[N],res[N],ans;

struct node{
    int l,r,id;
}q[N];
bool cmp(node a,node b)
{
    return a.l/block!=b.l/block?a.l/block<b.l/block:a.r<b.r;
}
void update(int p,int val)
{
    cnt[a[p]]+=val;
    if(cnt[a[p]]==1&&val==1)ans++;
    if(cnt[a[p]]==0&&val==-1)ans--;
//    printf("fuck %d %d %d\n",cnt[a[p]],ans,val);
}
int main()
{
    int n;
    scanf("%d",&n);
    block=sqrt(n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
    }
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    sort(q+1,q+1+m,cmp);
    ans=0;
//    printf("test\n");
    for(int i=1,l=1,r=0;i<=m;i++){
        for(;r<q[i].r;r++)
            update(r+1,1);
        for(;r>q[i].r;r--)
            update(r,-1);
        for(;l<q[i].l;l++)
            update(l,-1);
        for(;l>q[i].l;l--)
            update(l-1,1);
//        printf("test %d %d ans === %d\n",q[i].l,q[i].r,ans);
        res[q[i].id]=ans;
    }
    for(int i=1;i<=m;i++){
        printf("%d\n",res[i]);
    }
}

 

posted @ 2018-05-27 15:05  啦啦啦天啦噜  阅读(108)  评论(0编辑  收藏  举报