【BZOJ】【1878】【SDOI2009】HH的项链
树状数组/前缀和
Orz lct1999
好神的做法。。。
先看下暴力的做法:对于区间[l,r],我们依次扫过去,如果这个数是第一次出现,那么我们种类数+1。
我们发现:区间中相同的几个数,只有最左边那个才对答案有贡献。
那么我们O(n)预处理一个next数组,满足a[i]=a[next[i]],且i~next[i]这一段中没有与a[i]相等的数。。。。其实就是 i 右边第一个跟a[i]相等的值的下标啦。。
再回头看下我们的询问:对答案有贡献的数的特点是:它在整个序列中第一次出现,或者它是区间外某个数的next。在区间中再次出现的数,next指向它的数也一定也在区间中。
那么我们处理查询[l,r]时,我们可以将[1,l-1]的next[i]对答案的贡献+1,也就是我们维护一个ans数组,对ans[next[i]]++
答案就是ans[r]-ans[l-1](都是前缀和)
对询问进行左端点排序,树状数组维护一下即可……
(然而感觉蒟蒻并没有讲清楚……大家可以去看zyf神犇的blog:http://www.cnblogs.com/zyfzyf/p/3935617.html

1 /************************************************************** 2 Problem: 1878 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:920 ms 7 Memory:5768 kb 8 ****************************************************************/ 9 10 //BZOJ 1878 11 #include<cstdio> 12 #include<cstring> 13 #include<cstdlib> 14 #include<iostream> 15 #include<algorithm> 16 #define rep(i,n) for(int i=0;i<n;++i) 17 #define F(i,j,n) for(int i=j;i<=n;++i) 18 #define D(i,j,n) for(int i=j;i>=n;--i) 19 #define pb push_back 20 using namespace std; 21 typedef long long LL; 22 inline int getint(){ 23 int r=1,v=0; char ch=getchar(); 24 for(;!isdigit(ch);ch=getchar()) if (ch=='-') r=-1; 25 for(; isdigit(ch);ch=getchar()) v=v*10-'0'+ch; 26 return r*v; 27 } 28 const int N=50010,M=200010; 29 /*******************template********************/ 30 int n,m,num,a[N],c[N],now[N],fi[N],next[N],ans[M]; 31 struct que{int l,r,num;}q[M]; 32 bool operator < (const que &a,const que &b){return a.l<b.l;} 33 34 int b[N],d[N]; 35 void add(int x){ 36 d[x]++; 37 if (!x) return; 38 for(int i=x;i<=n;i+=i&(-i)) b[i]++; 39 } 40 int sum(int x){ 41 int r=0; 42 for(int i=x;i;i-=i&(-i)) r+=b[i]; 43 return r; 44 } 45 void init(){ 46 n=getint(); 47 F(i,1,n) c[i]=a[i]=getint(); 48 sort(c+1,c+n+1); 49 num=unique(c+1,c+n+1)-c-1; 50 F(i,1,n){ 51 a[i]=lower_bound(c+1,c+num+1,a[i])-c; 52 if (now[a[i]]){ 53 next[now[a[i]]]=i; 54 now[a[i]]=i; 55 }else{ 56 add(i); 57 now[a[i]]=i; 58 } 59 } 60 m=getint(); 61 F(i,1,m) q[i].l=getint(),q[i].r=getint(),q[i].num=i; 62 } 63 void solve(){ 64 sort(q+1,q+m+1); 65 int now=1; 66 F(i,1,m){ 67 while(now<q[i].l){ 68 add(next[now]); 69 now++; 70 } 71 ans[q[i].num]=sum(q[i].r)-sum(q[i].l-1); 72 } 73 F(i,1,m) printf("%d\n",ans[i]); 74 } 75 int main(){ 76 #ifndef ONLINE_JUDGE 77 freopen("1878.in","r",stdin); 78 freopen("1878.out","w",stdout); 79 #endif 80 init(); 81 solve(); 82 return 0; 83 }
1878: [SDOI2009]HH的项链
Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 2079 Solved: 1032
[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
1 2 3 4 3 5
3
1 2
3 5
2 6
Sample Output
2
2
4
2
4
HINT
对于20%的数据,N ≤ 100,M ≤ 1000;
对于40%的数据,N ≤ 3000,M ≤ 200000;
对于100%的数据,N ≤ 50000,M ≤ 200000。
【推荐】100%开源!大型工业跨平台软件C++源码提供,建模,组态!
【推荐】2025 HarmonyOS 鸿蒙创新赛正式启动,百万大奖等你挑战
【推荐】博客园的心动:当一群程序员决定开源共建一个真诚相亲平台
【推荐】开源 Linux 服务器运维管理面板 1Panel V2 版本正式发布
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有调度器的协程不是好协程,零基础深入浅出 C++20 协程
· 别做抢活的导演:代码中的抽象层次原则
· 从 Redis 客户端超时到 .NET 线程池挑战
· C23和C++26的#embed嵌入资源指南
· 「EF Core」框架是如何识别实体类的属性和主键的
· 阿里巴巴为什么禁止超过3张表join?
· 博客园众包线下沙龙第1期:云栖开发者基地,共建技术新天地
· 让 AI 帮我部署网站,太方便了!
· 别做抢活的导演:代码中的抽象层次原则
· .NET周刊【7月第1期 2025-07-06】