博客园 首页 私信博主 显示目录 隐藏目录 管理 动画

题解 【SDOI2009】HH的项链

题面

 

解析

这题本来莫队可以过的。

然而,对于某些加强的数据,莫队就得吸氧了。。

所以,本题解还将介绍另一种算法——树状数组。

首先,莫队就不用讲了吧(毕竟只是板子)。

那么,开始进入正题(似乎有点啰嗦)

我们先将每个询问存下来(还是离线处理),

然后再以右端点为关键字从小到大排序。

然后,对于1~n中的每个点r,

记录下区间1~r中每种颜色最右边的位置,

即在树状数组中将每种颜色最右边的位置设为1。

显然,如果询问q的右端点正好为r的话,

那么对于q的左端点l,

这种记录方式是最优的。

因为如果不是记录的最右边的点的话,就有可能忽略。

所以,先把询问按右端点排序,

再O(n)扫一遍,

并用树状数组计算前缀和,统计答案就行了

 

具体看代码吧:

#include<bits/stdc++.h>
#define lowbit(a) (a&(-a))
using namespace std;

inline int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0' && ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return f*sum;
}

const int MAXN=500001;
struct node{
    int l,r,id;
}q[MAXN];
int n,m;
int ans[MAXN],t[MAXN],a[MAXN];
int pla[MAXN*2];

bool cmp(node a,node b){
    return a.r<b.r;
}

inline void add(int x,int k){
    for(int i=x;i<=n;i+=lowbit(i)){
        t[i]+=k;
    }    
}

inline int ask(int x){
    int ret=0;
    for(int i=x;i;i-=lowbit(i)){
        ret+=t[i];
    }
    return ret;
}

int main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    m=read();
    for(int i=1;i<=m;i++) q[i].l=read(),q[i].r=read();
    for(int i=1;i<=m;i++) q[i].id=i;
    sort(q+1,q+m+1,cmp);
    int p=1;
    for(int i=1;i<=n;i++){
        if(pla[a[i]]){
            add(pla[a[i]],-1);
        }
        add(i,1);pla[a[i]]=i;
        while(q[p].r==i){
            ans[q[p].id]=ask(i)-ask(q[p].l-1);
            p++;
        }
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

 

posted @ 2019-03-20 11:17  Hastin  阅读(131)  评论(0编辑  收藏  举报