HH的项链(树状数组+离线处理)

1878: [SDOI2009]HH的项链


题目描述

HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此, 他的项链变得越来越长。有一天,他突然提出了一个问题:某一段贝壳中,包含了多少种不同 的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只好求助睿智的你,来解 决这个问题。

输入

第一行:一个整数N,表示项链的长度。 第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。 第三行:一个整数M,表示HH询问的个数。 接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。

输出

M行,每行一个整数,依次表示询问对应的答案。

样例输入

6
1 2 3 4 3 5
3
1 2
3 5
2 6

样例输出

2
2
4

提示


对于20%的数据,N ≤ 100,M ≤ 1000;
对于40%的数据,N ≤ 3000,M ≤ 200000;
对于100%的数据,N ≤ 50000,M ≤ 200000。

解析

这是一个树状数组+离线处理的T;

先将询问按L排序,再一维循环边将每个询问L之前有重复的数在下一个位置的统计个数+1(next[]和树状数组自己预处理写吧)

#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,a[50002],tr[50002],x;
int maxi=0,fs[1000002]={0},next[50002]={0};
struct node{
    int x,y,id,ans;
}q[200002];
int max(int a,int b){return a>b?a:b;}
bool rule1(node a,node b){
    return a.x==a.y?a.y<b.y:a.x<b.x;
}
bool rule2(node a,node b){
    return a.id<b.id;
}
int lowbit(int x){
    return x&(-x);
}
void updata(int x,int v){     //求树状数组
    for(int i=x;i<=n;i+=lowbit(i)){
        tr[i]+=v;
    }
}
int visit(int x){             //求a[1]~a[x]的和 
    int tmp=0;
    for(int i=x;i>0;i-=lowbit(i)){
        tmp+=tr[i];
    }
    return tmp;
}
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%d",a+i);
        maxi=max(maxi,a[i]);
    }
    for(int i=n;i>=1;i--) next[i]=fs[a[i]],fs[a[i]]=i;
    for(int i=1;i<=maxi;i++) 
        if(fs[i]) updata(fs[i],1);
    scanf("%d",&m);
    for(int i=1;i<=m;i++) scanf("%d%d",&q[i].x,&q[i].y),q[i].id=i;
    sort(q+1,q+m+1,rule1);      //按q[i].x排序 
    x=1;
    for(int i=1;i<=m;i++){
        while(x<q[i].x){                 //将q[i].x之前有重复值的数的下一次出现位置所统计的个数tr[next[x]]++
            if(next[x]) updata(next[x],1);
            x++;
        }
        q[i].ans=visit(q[i].y)-visit(q[i].x-1);
    }    
    sort(q+1,q+m+1,rule2);      //按q[i].id排序 
    for(int i=1;i<=m;i++) printf("%d\n",q[i].ans);
    return 0;
}
View Code

 

posted @ 2016-07-28 08:42  qg1  阅读(299)  评论(0编辑  收藏  举报