bzoj2743: [HEOI2012]采花

树状数组,离线处理。

首先把询问按左端点的大小升序排序。

从左往右扫描的过程中,将一个颜色第一次出现的位置变为0,第二次出现的位置变为1.

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 1000000 + 10;

struct Query {
    int l,r,id;
}q[maxn];

struct BIT {
    int a[maxn];
    int n;
    
    inline int lowbit(int x) {
        return x&-x;    
    }
    
    int query(int x) {
        int res=0;
        for(int i=x;i;i-=lowbit(i)) 
            res+=a[i];
        return res;    
    }
    
    void add(int x,int val) {
        for(int i=x;i<=n;i+=lowbit(i))
            a[i]+=val;
    }
    
    void init(int n2) {
        n=n2;
        memset(a,0,sizeof(a));    
    }
}bit;

bool cmp(Query a, Query b) {
    return a.l<b.l || (a.l==b.l && a.r<b.r);
}

int n,c,m,l;
int a[maxn],next[maxn],p[maxn],ans[maxn];

int main() {
    scanf("%d%d%d",&n,&c,&m);
    bit.init(n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    for(int i=n;i>=1;i--) {
        next[i]=p[a[i]];
        p[a[i]]=i;    
    }
    for(int i=1;i<=c;i++) if(next[p[i]]) 
        bit.add(next[p[i]],1);
    for(int i=1;i<=m;i++) {
        scanf("%d%d",&q[i].l,&q[i].r);
        q[i].id=i;
    }
    
    sort(q+1,q+m+1,cmp);
    
    l=1;
    for(int i=1;i<=m;i++) {
        while(l<q[i].l) {
            if(next[l]) bit.add(next[l],-1);
            if(next[next[l]]) bit.add(next[next[l]],1);
            l++;
        }
        ans[q[i].id]=bit.query(q[i].r)-bit.query(q[i].l-1);
    }
    for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
    return 0;    
}
posted @ 2016-06-14 20:10  invoid  阅读(147)  评论(0编辑  收藏  举报