[CF813E]Army Creation
题目大意:有$n$个数,$q$次询问,每次询问$[l,r]$中最多可以选多少个数使得相同的数最多有$k$个。($k$在同个测试点中相同)
题解:$k$不变,可以预处理出每个数前面的第$k$个相同的数在哪,对于询问区间$[l,r]$,若前面的第$k$个数的位置小于$l$,则可以选择这个数。于是用主席树维护一段值域中数的个数即可
卡点:无
C++ Code:
#include <cstdio> #include <vector> #include <algorithm> #define maxn 100010 #define N (maxn * 20) std::vector<int> pos[maxn]; int n, k, m; int rt[maxn], V[N], lc[N], rc[N], idx; void insert(int &rt, int l, int r, int num) { lc[++idx] = lc[rt], rc[idx] = rc[rt], V[idx] = V[rt] + 1, rt = idx; if (l == r) return ; int mid = l + r >> 1; if (num <= mid) insert(lc[rt], l, mid, num); else insert(rc[rt], mid + 1, r, num); } int query(int L, int R, int l, int r, int num) { if (r <= num) return V[R] - V[L]; int mid = l + r >> 1, ans = 0; ans = query(lc[L], lc[R], l, mid, num); if (num > mid) ans += query(rc[L], rc[R], mid + 1, r, num); return ans; } int main() { scanf("%d%d", &n, &k); for (int i = 1, x; i <= n; i++) { scanf("%d", &x); pos[x].push_back(i); int sz = pos[x].size(); if (sz > k) sz = pos[x][sz - k - 1]; else sz = 0; rt[i] = rt[i - 1]; insert(rt[i], 0, n, sz); } scanf("%d", &m); int last = 0; while (m --> 0) { int l, r; scanf("%d%d", &l, &r); l = (l + last) % n + 1, r = (r + last) % n + 1; if (l > r) std::swap(l, r); printf("%d\n", last = query(rt[l - 1], rt[r], 0, n, l - 1)); } return 0; }