BZOJ1878 [SDOI2009]HH的项链 树状数组 或 莫队

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ1878


题意概括

  给出一个长度为n的序列,用m次询问,问区间Li~Ri中有多少种不同的数。

  0<=数值<=1000000,n<=50000,m<=200000


题解

  本题有许多做法。

  这里介绍树状数组和莫队,都是离线算法。

  树状数组

  我们把序列按照R从小到大排序。

  然后从左往右走。

  依次加入数字,当前的状态,比如说搞定了前i个数字。

  对于第i+1个数字,我们要给它做一个标记,但是不可以重复,那么最优的方案就是把它之前的那个位置的+1标记删除,放到这里来。

  于是对于搞定前i个数的时候,有且一定有对于某一个数值,如果它出现过,那么它的+1标记在最后出现的那个地方。

  为什么可以?因为R是递增的!

  然后就是维护一个点修改和区间和的东西了。秒选树状数组。

  莫队

  莫队就是最裸的莫队。

  先把1~n的区间尽量平均的分成sqrt(n)块。

  把所有的询问以L所在的块为第一关键字升序,R为第二关键字升序排序。

  然后就是大暴力。

  朴素的写法有点长。

  但是压缩之后短的无厘头……


代码

 

  代码1 - 树状数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=50000+5,M=200000+5,V=1000000+5;
int n,m,a[N],c[N],pos[V];
struct Query{
    int L,R,bh,ans;
    bool operator < (const Query x) const {
        return R<x.R;
    }
}q[M];
bool cmpbh(Query a,Query b){
    return a.bh<b.bh;
}
int lowbit(int x){
    return x&-x;
}
void add(int x,int d){
    if (!x)
        return;
    for (;x<=n;x+=lowbit(x))
        c[x]+=d;
}
int sum(int x){
    int ans=0;
    for (;x>0;x-=lowbit(x))
        ans+=c[x];
    return ans;
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&m);
    for (int i=1;i<=m;i++){
        scanf("%d%d",&q[i].L,&q[i].R);
        q[i].bh=i;
    }
    sort(q+1,q+m+1);
    memset(pos,0,sizeof pos);
    memset(c,0,sizeof c);
    for (int i=1,j=0;i<=m;i++){
        while (j<q[i].R){
            j++;
            add(pos[a[j]],-1);
            pos[a[j]]=j;
            add(pos[a[j]],1);
        }
        q[i].ans=sum(q[i].R)-sum(q[i].L-1);
    }
    sort(q+1,q+m+1,cmpbh);
    for (int i=1;i<=m;i++)
        printf("%d\n",q[i].ans);
    return 0;
}

 

  代码2 - 莫队

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=50000+5,M=200000+5,V=1000000+5;
int n,m,size,a[N],cnt[V];
struct Query{
    int L,R,bh,ans;
}q[M];
bool cmpmd(Query a,Query b){
    int k1=a.L/size,k2=b.L/size;
    if (k1!=k2)
        return k1<k2;
    return a.R<b.R;
}
bool cmpbh(Query a,Query b){
    return a.bh<b.bh;
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&m);
    for (int i=1;i<=m;i++){
        scanf("%d%d",&q[i].L,&q[i].R);
        q[i].bh=i;
    }
    size=sqrt(n)+0.5;
    memset(cnt,0,sizeof cnt);
    sort(q+1,q+m+1,cmpmd);
    for (int i=1,tot=0,L=1,R=0;i<=m;i++){
        while (R<q[i].R){
            R++;
            if (cnt[a[R]]==0)
                tot++;
            cnt[a[R]]++;
        }
        while (L>q[i].L){
            L--;
            if (cnt[a[L]]==0)
                tot++;
            cnt[a[L]]++;
        }
        while (R>q[i].R){
            cnt[a[R]]--;
            if (cnt[a[R]]==0)
                tot--;
            R--;
        }
        while (L<q[i].L){
            cnt[a[L]]--;
            if (cnt[a[L]]==0)
                tot--;
            L++;
        }
        q[i].ans=tot;
    }
    sort(q+1,q+m+1,cmpbh);
    for (int i=1;i<=m;i++)
        printf("%d\n",q[i].ans);
    return 0;
}

 

  代码3 - 莫队+代码压缩

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include <cstring>
#include <cstdio>
#include <algorithm>
#include <cstdlib>
#include <cmath>
using namespace std;
const int N=50000+5,M=200000+5,V=1000000+5;
int n,m,size,a[N],cnt[V];
struct Query{
    int L,R,bh,ans;
}q[M];
bool cmpmd(Query a,Query b){
    int k1=a.L/size,k2=b.L/size;
    if (k1!=k2)
        return k1<k2;
    return a.R<b.R;
}
bool cmpbh(Query a,Query b){
    return a.bh<b.bh;
}
int main(){
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    scanf("%d",&m);
    for (int i=1;i<=m;i++)
        scanf("%d%d",&q[i].L,&q[i].R),q[i].bh=i;
    size=sqrt(n)+0.5;
    memset(cnt,0,sizeof cnt);
    sort(q+1,q+m+1,cmpmd);
    for (int i=1,tot=0,L=1,R=0;i<=m;i++){
        while (R<q[i].R)
            tot+=cnt[a[++R]]++==0;
        while (L>q[i].L)
            tot+=cnt[a[--L]]++==0;
        while (R>q[i].R)
            tot-=--cnt[a[R--]]==0;
        while (L<q[i].L)
            tot-=--cnt[a[L++]]==0;
        q[i].ans=tot;
    }
    sort(q+1,q+m+1,cmpbh);
    for (int i=1;i<=m;i++)
        printf("%d\n",q[i].ans);
    return 0;
}

  

posted @   zzd233  阅读(250)  评论(0编辑  收藏  举报
编辑推荐:
· Java 中堆内存和栈内存上的数据分布和特点
· 开发中对象命名的一点思考
· .NET Core内存结构体系(Windows环境)底层原理浅谈
· C# 深度学习:对抗生成网络(GAN)训练头像生成模型
· .NET 适配 HarmonyOS 进展
阅读排行:
· 如何给本地部署的DeepSeek投喂数据,让他更懂你
· 超详细,DeepSeek 接入PyCharm实现AI编程!(支持本地部署DeepSeek及官方Dee
· 用 DeepSeek 给对象做个网站,她一定感动坏了
· .NET 8.0 + Linux 香橙派,实现高效的 IoT 数据采集与控制解决方案
· .NET中 泛型 + 依赖注入 的实现与应用

点击右上角即可分享
微信分享提示