Description
HH有一串由各种漂亮的贝壳组成的项链。HH相信不同的贝壳会带来好运,所以每次散步 完后,他都会随意取出一
段贝壳,思考它们所表达的含义。HH不断地收集新的贝壳,因此他的项链变得越来越长。有一天,他突然提出了一
个问题:某一段贝壳中,包含了多少种不同的贝壳?这个问题很难回答。。。因为项链实在是太长了。于是,他只
好求助睿智的你,来解决这个问题。
Input
第一行:一个整数N,表示项链的长度。
第二行:N个整数,表示依次表示项链中贝壳的编号(编号为0到1000000之间的整数)。
第三行:一个整数M,表示HH询问的个数。
接下来M行:每行两个整数,L和R(1 ≤ L ≤ R ≤ N),表示询问的区间。
N ≤ 50000,M ≤ 200000。
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
这题,这题,这题,毒瘤!!!
卡我分块!!!
1.分块做法
虽然是莫队经典题但是还是想写分块啊
可以保存每个点往前第一个与他颜色相同的点的坐标
假设它为$pre$中,那么我们要找的就是区间内的$pre$小于$L$的值的数量,因为$pre$大于$L$的数,一定在区间内出现了至少两次。这个可以画个图想想,想明白了基本就懂这题怎么用分块写了
那么对块内元素进行排序,查询的时候二分查找就行,散块直接暴力查找
查询的总复杂度是$O(m*log(\sqrt{n})*\sqrt{n})$
这复杂度很擦边...然后万恶的bzoj时限开4s,就死活卡不过去了...已经尝试了$fread$,$fwrite$,$inline$,$register$,以及各种奇奇怪怪的块的大小
都卡不过去...
评测记录
中间那次WA是因为调试的东西没删
不断增长的代码量说明了一切....
在洛谷交了一下是80分
如果哪位大大分块卡过去这题的话跟我讲一下卡法...
这里放一下我的分块代码,就不贴那些加了一堆优化的了,贴最原始的
#include <bits/stdc++.h> using namespace std; int n,m,a[50010],pre[50010],p[1000010]; int block,num,l[50010],r[50010],belong[50010],sum[50010]; void build(){ block=sqrt(n); num=n/block; if(n%block)num++; for(int i=1;i<=num;i++){ l[i]=block*(i-1)+1; r[i]=block*i; } r[num]=n; for(int i=1;i<=n;i++){ belong[i]=(i-1)/block+1; sum[i]=pre[i]; } for(int i=1;i<=num;i++){ sort(sum+l[i],sum+r[i]+1); } } int find(int L,int R,int x){ while(L<=R){ int mid=(L+R)>>1; if(sum[mid]<x)L=mid+1; else R=mid-1; } return L; } int query(int L,int R){ int ans=0; if(belong[L]==belong[R]){ for(int i=L;i<=R;i++){ if(pre[i]<L)ans++; } return ans; } for(int i=L;i<=r[belong[L]];i++){ if(pre[i]<L)ans++; } for(int i=l[belong[R]];i<=R;i++){ if(pre[i]<L)ans++; } for(int i=belong[L]+1;i<=belong[R]-1;i++){ ans+=find(l[i],r[i],L)-l[i]; } return ans; } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); pre[i]=p[a[i]]; p[a[i]]=i; } build(); scanf("%d",&m); while(m--){ int fl,fr; scanf("%d%d",&fl,&fr); printf("%d\n",query(fl,fr)); } return 0; }