zoukankan      html  css  js  c++  java
  • BZOJ 1878: [SDOI2009]HH的项链

    1878: [SDOI2009]HH的项链

    Time Limit: 4 Sec  Memory Limit: 64 MB
    Submit: 3547  Solved: 1756
    [Submit][Status][Discuss]

    Description

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

    Input

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

    Output

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

    Sample Input

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

    Sample Output

    2
    2
    4

    HINT


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

    Source

    分析:

    此题做法很多...这里主要贴上两种离线做法

    No.1莫队

    这就不用说了...和小Z的袜子做法相同...详见http://www.cnblogs.com/neighthorn/p/6202794.html

    No.2树状数组

    以前看过一道类似的题目(具体是啥不记得了)….所以这次还有点思路… 
    我们考虑如果没有重复的数字直接算就好了…有重复的数字就应该每个数字只计算一次…怎么实现这种思想…. 
    考虑对于一个询问,第一次出现的数字就是最靠左的数字,那么我们就把这个区间中第一次出现的数字设为1,求个前缀和就好了… 
    所以说我们可以离线做…把所有询问按照左端点排序…对于当前的询问答案就直接计算前缀和就好…计算完之后,对于s[i].l~s[i+1].l-1这些数字,insert(j,-1),insert(nxt[j],1),这样就保证了对于当前的询问数组中设为1的数字都是不重复的….而且也不会漏掉一些数字…

    感觉这种思想还是很常用的...

    代码:

    No.1莫队:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<map>
     6 //by NeighThorn
     7 using namespace std;
     8 
     9 const int maxn=50000+5,maxm=200000+5,blo=223;
    10 
    11 int n,m,tot,tmp,a[maxn],id[maxn],cnt[maxn];
    12 
    13 map<int,int> mp;
    14 
    15 struct M{
    16     int l,r,num,ans;
    17 }q[maxm];
    18 
    19 inline bool cmp1(M x,M y){
    20     if(id[x.l]==id[y.l])
    21         return x.r<y.r;
    22     return x.l<y.l;
    23 }
    24 
    25 inline bool cmp2(M x,M y){
    26     return x.num<y.num;
    27 }
    28 
    29 inline void change(int pos,int x){
    30     if(cnt[a[pos]]==0&&cnt[a[pos]]+x==1)
    31         tmp++;
    32     else if(cnt[a[pos]]==1&&cnt[a[pos]]+x==0)
    33         tmp--;
    34     cnt[a[pos]]+=x;
    35 }
    36 
    37 signed main(void){
    38     tot=0;
    39     scanf("%d",&n);
    40     memset(cnt,0,sizeof(cnt)); 
    41     for(int i=1,x;i<=n;i++){
    42         scanf("%d",&x);
    43         if(mp.find(x)==mp.end())
    44             mp[x]=++tot;
    45         a[i]=mp[x];
    46     }scanf("%d",&m);
    47     for(int i=1;i<=n;i++)
    48         id[i]=(i-1)/blo+1;
    49     for(int i=1;i<=m;i++)
    50         scanf("%d%d",&q[i].l,&q[i].r),q[i].num=i;
    51     sort(q+1,q+m+1,cmp1);tmp=0;
    52     for(int i=1,l=1,r=0;i<=m;i++){
    53         for(;l<q[i].l;l++)
    54             change(l,-1);
    55         for(;l>q[i].l;l--)
    56             change(l-1,1);
    57         for(;r<q[i].r;r++)
    58             change(r+1,1);
    59         for(;r>q[i].r;r--)
    60             change(r,-1);
    61         q[i].ans=tmp;
    62     }
    63     sort(q+1,q+m+1,cmp2);
    64     for(int i=1;i<=m;i++)
    65         printf("%d
    ",q[i].ans);
    66     return 0;
    67 }
    View Code

    No.2树状数组:

     1 #include<algorithm>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 //by NeighThorn
     6 using namespace std;
     7 const int maxn=50000+5,maxm=1000000+5;
     8 int n,m,a[maxn],tr[maxn],pos[maxm],nxt[maxn];
     9 struct M{
    10     int l,r,id,ans; 
    11 }s[200000+5];
    12 inline bool cmp1(M a,M b){
    13     if(a.l==b.l)
    14         return a.r<b.r;
    15     return a.l<b.l;
    16 }
    17 inline bool cmp2(M a,M b){
    18     return a.id<b.id;
    19 }
    20 inline void insert(int x,int y){
    21     for(;x<=1000000;x+=x&(-x))
    22         tr[x]+=y;
    23 }
    24 inline int query(int x){
    25     int sum=0;
    26     for(;x;x-=x&(-x))
    27         sum+=tr[x];
    28     return sum;
    29 }
    30 signed main(void){
    31     scanf("%d",&n);memset(tr,0,sizeof(tr));
    32     memset(pos,0,sizeof(pos));
    33     for(int i=1;i<=n;i++){
    34         scanf("%d",&a[i]);
    35         if(pos[a[i]]==0)
    36             insert(i,1),pos[a[i]]=i;
    37         else
    38             nxt[pos[a[i]]]=i,pos[a[i]]=i;
    39     }
    40     scanf("%d",&m);
    41     for(int i=1;i<=m;i++)
    42         scanf("%d%d",&s[i].l,&s[i].r),s[i].id=i;
    43     sort(s+1,s+m+1,cmp1);s[0].l=0;
    44     for(int i=1;i<=m;i++){
    45         s[i].ans=query(s[i].r);
    46         if(i<m&&s[i].l!=s[i+1].l)
    47             for(int j=s[i].l;j<s[i+1].l;j++){
    48                 insert(j,-1);
    49                 if(nxt[j])
    50                     insert(nxt[j],1);
    51             }
    52     }
    53     sort(s+1,s+m+1,cmp2);
    54     for(int i=1;i<=m;i++)
    55         printf("%d
    ",s[i].ans);
    56     return 0;
    57 }
    58 
    View Code

    by NeighThorn

  • 相关阅读:
    BZOJ2298: [HAOI2011]problem a
    BZOJ4066: 简单题
    BZOJ2131: 免费的馅饼
    Educational Codeforces Round 97 div2
    [SCOI2016]背单词
    [SCOI2015]情报传递(离线树状数组跑图)
    树上主席树(无代码,单纯谈思路的一篇水文)
    CF Round #679 div2赛后总结
    [SCOI2015]小凸解密码(平衡树、线段树做法)
    CF Round #677 div3 赛后总结
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6203092.html
Copyright © 2011-2022 走看看