bzoj1878 [SDOI2009]HH的项链

1878: [SDOI2009]HH的项链

Time Limit: 4 Sec  Memory Limit: 64 MB

Description

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

Input

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

Output

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

Sample Input

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

Sample Output

2
2
4

HINT

 

Source

Tips:

  这道题你很容易想到用一些线段树,树状数组之类的算法;

  但是却很难用上去;

  因为它是离线的;

  我们可以有序的处理询问,以询问左端点排序;

  现将每个数第一次出现的位置赋值为一,维护一棵线段树,并记录每个数的下一个重复的数的位置;

  当处理到了第i个询问,那么前l[i]个数已经不需要了,将前l[i]个数上的一,转移到next[i]上,做一遍线段树的询问;

Code:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#define MAXN 100008
using namespace std;
int n,m,tree[2*MAXN],a[MAXN],next[MAXN],boo[MAXN*10],pre[MAXN];
int ans[2*MAXN];

struct node{
    int x,y,pos;
}f[MAXN*2];

int query(int l,int r,int li,int ri,int v){
    if(l==li&&r==ri){
        return tree[v];
    }
    int mid=(l+r) >> 1;
    if(ri<=mid){
        return query(l,mid,li,ri,v<<1);
    }
    if(li>mid){
        return query(mid+1,r,li,ri,(v<<1)+1);
    }
    return query(l,mid,li,mid,v<<1)+query(mid+1,r,mid+1,ri,(v<<1)+1);
}

void add(int l,int r,int flag,int v){
    if(l==r){
        tree[v]=1;
        return;
    }
    int mid=(l+r) >> 1;
    if(flag<=mid)
        add(l,mid,flag,v<<1);
    else
        add(mid+1,r,flag,(v<<1)+1);
    tree[v]=tree[v<<1]+tree[(v<<1)+1];
}

bool cmp(node aa,node bb){
    return aa.x<bb.x;
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        scanf("%d",&a[i]);
        if(!boo[a[i]]){
            add(1,n,i,1);
            boo[a[i]]=i;
        }else{
            pre[i]=boo[a[i]];
            boo[a[i]]=i;
            next[pre[i]]=i;
        }
    }
    scanf("%d",&m);
    for(int i=1;i<=m;i++){
        scanf("%d%d",&f[i].x,&f[i].y);
        f[i].pos=i;
    }
    f[0].x=1;
    sort(f+1,f+m+1,cmp);
    for(int j=1;j<=m;j++){
        for(int i=f[j-1].x;i<f[j].x;i++){
            add(1,n,next[i],1);
        }
        ans[f[j].pos]=query(1,n,f[j].x,f[j].y,1);
    }
    for(int i=1;i<=m;i++)
        printf("%d
",ans[i]);
}
原文地址:https://www.cnblogs.com/WQHui/p/7536487.html