附加题2
(第一篇题解)
询问区间内出现K次的数字有多少个,比赛的时候看到这个题想起主席树 (然而我主席树并不熟),比完赛才知道这个题是可以用莫队解的,所以去学了莫队。
莫队是一种优雅的暴力算法,结合分块降低时间复杂度
本题我转移区间内信息的方法为:
1、vis[]数组:vis[i]保存区间内股票i出现多少次
2、res[]数组:res[i]保存区间内出现i次的股票有多少张
3、有这两个数组接下来考虑问题区间左端点小于枚举的l的情况,此时需要向左枚举并用vis[]数组记录票出现次数,将此时股票新增的出现次数记录到res[]数组里面,并将更新vis[]数组之前的res[]数组中记录的旧影响减掉。
4、问题区间右端点大于枚举的r时同理
5、考虑区间左端点大于枚举的l的情况,此时需要向右减掉所有多余的影响,将此时股票的出现次数减小并记录到res[]数组里面,并将更新vis[]数组之前的res[]数组中记录的旧影响减掉。(注意两次的旧影响不一样,因为一次是vis[]++,一次是vis[]--)
6、问题区间右端点小于枚举的r时同理
代码部分:
#include <bits/stdc++.h> using namespace std; const int maxn = 4e4 + 5; inline int read() { int x = 0; char c = getchar(); while(!isdigit(c)) c = getchar(); while(isdigit(c)) x = (x << 1) + (x << 3) + (c ^ 48), c = getchar(); return x; } int pos[maxn],nums[maxn],vis[maxn],res[maxn];//vis数组用来保存股票出现的次数 struct node { int start,endd,k,idx,ans; } sakura[maxn]; inline bool cmp1(node a,node b) {return pos[a.start] == pos[b.start] ? a.endd < b.endd : pos[a.start] < pos[b.start];} inline bool cmp2(node a,node b) {return a.idx < b.idx; } inline void add(int n) {vis[nums[n]]++, res[vis[nums[n]] - 1]--, res[vis[nums[n]]]++; } inline void sub(int n) {vis[nums[n]]--, res[vis[nums[n]]]++, res[vis[nums[n]] + 1]--; } int main() { int n = read(), m = read(); int base = sqrt(n); for(int i = 1; i <= n; i++) nums[i] = read(), pos[i] = i / base; for(int i = 1; i <= m; i++) sakura[i].start = read(), sakura[i].endd = read(),sakura[i].k = read(),sakura[i].idx = i; sort(sakura + 1,sakura + 1 + m,cmp1); int l = 1,r = 0; for(int i = 1; i <= m; i++) { while(sakura[i].start < l) add(--l); while(sakura[i].endd > r) add(++r); while(sakura[i].start > l) sub(l++); while(sakura[i].endd < r) sub(r--); sakura[i].ans = res[sakura[i].k]; // debug 可以不管 // cout << "=============================" << endl; // cout << i << " " << sakura[i].start << " " << sakura[i].endd << endl; // for(int i = 0; i <= 5; i++) printf("%d%c",res[i],i == 5 ? '\n' : ' '); // cout << "=============================" << endl; } sort(sakura + 1,sakura + 1 + m,cmp2); for(int i = 1; i <= m; i++) printf("%d\n",sakura[i].ans); }