BZOJ1878 [SDOI2009] HH的项链(树状数组)

树状数组求区间不同种类的数模板

 

树状数组来存储前缀和,对于每个数我们记录他上一次出现的位置,

把查询按照右端点从小到大排序

对于每个数我们对add(pre[i],-1) add(i,1);

每个数字只有他当前最后一个位置贡献次数(查询区间已排序)

最后sum[r]-sum[l-1]就是答案

 

/**************************************************************
    Problem: 1878
    User: Minun
    Language: C++
    Result: Accepted
    Time:1728 ms
    Memory:10276 kb
****************************************************************/
 
#include<bits/stdc++.h>
  
using namespace std;
  
const int maxn=1e6+10;
const double EPS=1e-12;
  
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
 
int tree[50005];
int ans[600005],pre[50005];
 
int vis[maxn];
 
int n;
 
struct node{
    int l,r,id;
}e[200005];
  
inline int lowbit(int x)
{
    return x&(-x);
}
  
inline void add(int x,int val)
{
    while(x<=n)
    {
        tree[x]+=val;
        x+=lowbit(x);
    }
}
  
inline int sum(int x)
{
    int temp=0;
    while(x>0)
    {
        temp+=tree[x];
       // x=x&(x-1);
        x-=lowbit(x);
    }
    return temp;
}
  
  
  
int cmp(node a,node b)
{
    return a.r==b.r?a.l<b.l:a.r<b.r;
}
  
  
int main()
{

    scanf("%d",&n);
    int now;
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&now);
        pre[i]=vis[now];
        vis[now]=i;
    }
    int m;
    scanf("%d",&m);
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d",&e[i].l,&e[i].r);
        e[i].id=i;
    }
  
    sort(e+1,e+1+m,cmp);
    int st=1;
    st=0;
    for(int i=1;i<=m;i++)
    {
  
        while(st<e[i].r)
        {
            st++;
            if(pre[st])
            {
  
                add(pre[st],-1);
            }
            add(st,1);
        }
        ans[e[i].id]=sum(e[i].r)-sum(e[i].l-1);
    }
    for(int i=1;i<=m;i++)
    {
        printf("%d\n",ans[i]);
    }
    return 0;
}

 

posted @ 2019-05-20 19:48  Minun  阅读(98)  评论(0编辑  收藏  举报