• bzoj1878[SDOI2009]HH的项链


    bzoj1878[SDOI2009]HH的项链

    题意:

    N个数,M个询问求区间[L,R]中包含了多少种不同的数。

    题解:

    莫队好像可以做~但正解是树状数组。先将询问按左端点排序,并求出每个数的下一个与它相等的数的位置,同时将每个数第一次出现的位置在树状数组中置为1,此时query(x)求出来的就是1到x里有多少个不同的数。枚举排序后的询问,将当前左端点向右移动,每右移一位就将原位置的数的下一个与它相同的数的位置在树状数组中置为1,保证如果这个数在[l,r]中出现不会漏算。当左端点移动到询问的左端点位置时,就输出query(r)-query(l-1),表示l到r里有多少个不同的数。

    代码:

     1 #include <cstdio>
     2 #include <cstring>
     3 #include <algorithm>
     4 #define inc(i,j,k) for(int i=j;i<=k;i++)
     5 #define maxn 50100
     6 #define lb(x) x&-x;
     7 using namespace std;
     8 
     9 int a[maxn],last[maxn*20],next[maxn],sm[maxn],n,m;
    10 struct ask{int l,r,ans,id;}; ask asks[maxn*6];
    11 bool cmp1(ask a,ask b){return a.l<b.l;}
    12 bool cmp2(ask a,ask b){return a.id<b.id;}
    13 inline void update(int x,int v){while(x<=n){sm[x]+=v,x+=lb(x);}}
    14 inline int query(int x){int q=0; while(x>0){q+=sm[x],x-=lb(x);} return q;}
    15 int main(){
    16     scanf("%d",&n); inc(i,1,n)scanf("%d",&a[i]);
    17     scanf("%d",&m); inc(i,1,m)scanf("%d%d",&asks[i].l,&asks[i].r),asks[i].id=i;
    18     memset(last,0,sizeof(last)); inc(i,1,n){if(last[a[i]])next[last[a[i]]]=i;else update(i,1); last[a[i]]=i;}
    19     sort(asks+1,asks+1+m,cmp1); int l=1;
    20     inc(i,1,m){
    21         while(l<asks[i].l){if(next[l])update(next[l],1); l++;}
    22         asks[i].ans=query(asks[i].r)-query(asks[i].l-1);
    23     }
    24     sort(asks+1,asks+1+m,cmp2); inc(i,1,m)printf("%d
    ",asks[i].ans);
    25     return 0;
    26 }

    20160525

  • 相关阅读:
    系统分析记录rocketmq导致jvm线程数量大
    值得被提拔的人,往往具备以下几点特质
    上周热点回顾(7.187.24)
    上周热点回顾(8.18.7)
    上周热点回顾(7.47.10)
    上周热点回顾(8.88.14)
    上周热点回顾(7.117.17)
    上周热点回顾(8.158.21)
    下一步,敏捷!| 助力远程办公走向成功系列讲座
    上周热点回顾(7.257.31)
  • 原文地址:https://www.cnblogs.com/YuanZiming/p/5698469.html
Copyright © 2020-2023  润新知