输入并分段,然后排序,伪代码如下,先将输入进来的查询,按照左节点所在的段的先后和右节点的前后排序。bool cmp(const aa &a1,const aa &a2){ if(a1.t
这里来单独解释一下开的变量的用处struct aa{ int l,r,k,bian,t;//左节点,右节点,在范围[ L,R ]中至少重复K次的数字的个数,编号;//最后一个可有可无,这里只是为了方便分块排序}p[100001];int n,m,a[100001],q,ans[100001];//这些好理解吧,我就不解释了int cnt[100001],num[100001];//num[j]存j出现的次数,cnt[k]存出现不少于k次的数有几个
先预处理一遍第一个查询(排完序后)的cnt和num,具体代码如下 for(int i=p[1].l;i<=p[1].r;i++)num[a[i]]++,cnt[num[a[i]]]++; ans[p[1].bian]=cnt[p[1].k];
然后从第二个到第m个开始搜索,开始不断更新cnt和num,记住,修改p[i-1].l或p[i+1].l、更改num和更改cnt的顺序你要自己理解,不能改顺序for(int i=2;i<=m;i++) { while(p[i-1].l>p[i].l){p[i-1].l--;num[a[p[i-1].l]]++,cnt[num[a[p[i-1].l]]]++;}//如果之前那个查询的左节点在当前查询的左节点的右边,将之前查询的左节点往左移知道与当前查询的左节点重合,并在移的过程中不断更新cnt和num值,下面三条语句也是这个用处。 while(p[i-1].l
p[i].r){cnt[num[a[p[i-1].r]]]--,num[a[p[i-1].r]]--;p[i-1].r--;} while(p[i-1].r
最后输出答案,这没什么好说的for(int i=1;i<=m;i++)printf('%d\n',ans[i]);
样例输入10 3 1 2 3 1 1 2 1 2 3 1 1 4 1 1 10 22 7 1 样例输出333
先将查询排序拍后的结果1 4 12 7 11 10 2
先预处理第一个
接着查找第二个,不断移动左右指针,更改cnt和num值
查找第三个,同第二个的方法
记住,排序不是排数组中的数,而是查找的数
排序前用结构体,记得保存每个查询在输入中的位置,方便输出