首页 > 其他 > 详细

SDOI2009 HH的项链

时间:2019-11-14 09:49:17      阅读:82      评论:0      收藏:0      [点我收藏+]

题目传送门

技术分享图片

这题是一道很好的莫队树状数组题目。

首先,我们需要离线操作,把询问全存下来,然后按询问的右端点排序

排好序后,我们可以更改树状数组维护的区间,同时记录每一个元素最后出现的位置,因为我们是从左向右来回答每个询问,所以在右面的元素肯定比在左面的相同元素作用更大一些,所以我们在相同元素中只保存在我们当前维护的区间内且最靠右的一个就好了。

之后就可以用前缀和来处理答案了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lb i&-i
using namespace std;
int tree[1000010],n;
void add(int x,int k){
    for(int i=x;i<=n;i+=lb)
      tree[i]+=k;
}
int sum(int x){
    int anss=0;
    for(int i=x;i;i-=lb)
      anss+=tree[i];
    return anss;
}
struct zzz{
    int l,r,pos;
}q[200010];
bool cmp(zzz x,zzz y){
    if(x.r!=y.r) return x.r<y.r;
    else return x.l<y.l;
}
int read(){
    int k=0; char c=getchar();
    for(;c<'0'||c>'9';) c=getchar();
    for(;c>='0'&&c<='9';c=getchar())
      k=k*10+c-48;
    return k;
}
int a[500010],last[1000010],ans[200010];
int main(){
    n=read();
    for(int i=1;i<=n;i++) a[i]=read();
    int m=read();
    for(int i=1;i<=m;i++)
      q[i].l=read(),q[i].r=read(),q[i].pos=i;
    sort(q+1,q+m+1,cmp);
    int i=0;
    for(int j=1;j<=m;j++){
        while(i<q[j].r){  //i相当于一个指针,表示我们当前处理到哪
            i++;
            if(last[a[i]]){
                add(last[a[i]],-1); add(i,1); //及时更改
                last[a[i]]=i;
            }
            else{
                add(i,1); last[a[i]]=i;
            }
        }
        ans[q[j].pos]=sum(q[j].r)-sum(q[j].l-1); //处理询问
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;
}

SDOI2009 HH的项链

原文:https://www.cnblogs.com/morslin/p/11854751.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!