Description
有
个std::queue<int>
,编号为
到
。
对于第
个队列,当它的大小超过
时,它会执行pop()
知道大小不超过
。
每次操作为把
的队列push(x)
,
是给定的数。
每次执行完操作后,求所有队列中有多少种不同的数。
Solution
显然,当前插入的数再此队列被push
次后会被弹出。
如果求出来每次插入的数被全部弹出的时间 ,那么这道题就很好做了。
考虑把序列分块。
对于每次操作,它可以被拆分为若干个整块与 个散块。
首先考虑整块的贡献。显然,对于都包含了同一整块的操作,它们在这个整块的 是单调不降的。所以可以用two-pointer维护。
维护两个指针
,表示做完区间
的操作后,操作
加入的数会被全部弹出。设
表示当前块被完全覆盖了多少次,
表示队列
再被push
次就会把
弹掉。
为
的最大值。
考虑如何维护,当 左移即加入一个操作时,如果它覆盖了整块,那么把 加一。否则如果它和当前区间有交,则把有交的部分的 减一,重新计算 。当 左移即撤销一个操作时类似。
然后考虑散块的贡献。
在处理整块时,预处理如下的东西。
- 表示 次操作完整覆盖了当前块 次。
- 表示第 个完整覆盖整块的操作。
- 表示第 个未完整覆盖整块但有交的操作。
- 表示当有 个未完整覆盖整块但有交的操作时有 个完整覆盖整块的操作。
枚举每个散块里的位置 ,考虑它对 中操作的贡献。类似的,对于覆盖这个位置的操作,它们在这个位置的 也是单调的。
在 上维护双指针 。表示当执行完 的操作后,当前枚举位置的 已被弹出。维护一个 表示当前位置被覆盖的次数。
对于每个 , 不断往后跳直到 。然后分情况讨论在何时当前位置的 被弹出。
#include <bits/stdc++.h>
using namespace std;
const int maxn = 100005;
int n, m, S;
struct operation
{
int l, r, x;
} opt[maxn];
int cov, c_cnt, d_cnt, cnt, Max;
int a[maxn], b[maxn], s[maxn], c[maxn], d[maxn], e[maxn], ed[maxn];
map<int, int> f;
vector<int> vec[maxn];
inline int gi()
{
char c = getchar();
while (c < '0' || c > '9') c = getchar();
int sum = 0;
while ('0' <= c && c <= '9') sum = sum * 10 + c - 48, c = getchar();
return sum;
}
inline void chkmax(int &a, int b) {if (a < b) a = b;}
int main()
{
freopen("q1.in", "r", stdin);
//freopen("queue.in", "r", stdin);
freopen("queue.out", "w", stdout);
n = gi(); m = gi();
for (int i = 1; i <= n; ++i) a[i] = gi();
for (int i = 1; i <= m; ++i) opt[i] = (operation) {gi(), gi(), gi()};
S = sqrt(n);
for (int L = 1, R; L <= n; L += S) {
R = min(L + S - 1, n);
c_cnt = d_cnt = cov = Max = 0;
for (int i = L; i <= R; ++i) chkmax(Max, b[i] = a[i]);
for (int i = 1, j = 0; i <= m; ++i) {
if (opt[i].l <= L && R <= opt[i].r) --cov;
else if (opt[i].l <= R && L <= opt[i].r) {
for (int j = max(opt[i].l, L); j <= min(opt[i].r, R); ++j) ++b[j];
Max = 0;
for (int j = L; j <= R; ++j) chkmax(Max, b[j]);
}
while (j <= m && Max - cov > 0) {
++j;
if (opt[j].l <= L && R <= opt[j].r) ++cov;
else if (opt[j].l <= R && L <= opt[j].r) {
for (int k = max(opt[j].l, L); k <= min(opt[j].r, R); ++k) --b[k];
Max = 0;
for (int k = L; k <= R; ++k) chkmax(Max, b[k]);
}
}
s[i] = s[i - 1];
if (opt[i].l <= L && R <= opt[i].r) chkmax(ed[i], j), ++s[c[++c_cnt] = i];
else if (opt[i].l <= R && L <= opt[i].r) d[++d_cnt] = i, e[d_cnt] = c_cnt;
}
for (int i = L; i <= R; ++i) {
cnt = a[i];
for (int j = 1, k = 0; j <= d_cnt; ++j) {
cnt += s[d[j]] - s[d[j - 1]];
if (opt[d[j]].l <= i && i <= opt[d[j]].r) {
++cnt;
while (k < d_cnt && cnt > 0) ++k, cnt -= s[d[k]] - s[d[k - 1]] + (opt[d[k]].l <= i && i <= opt[d[k]].r);
if (cnt > 0) {
if (cnt > s[m] - s[d[k]]) ed[d[j]] = m + 1;
else chkmax(ed[d[j]], c[e[k] + cnt]);
continue;
}
if (opt[d[k]].l <= i && i <= opt[d[k]].r) chkmax(ed[d[j]], cnt ? c[e[k] + cnt + 1]: d[k]);
else chkmax(ed[d[j]], c[e[k] + cnt]);
}
}
}
}
for (int i = 1; i <= m; ++i) vec[i].push_back(opt[i].x), vec[ed[i]].push_back(-opt[i].x);
cnt = 0;
for (int i = 1; i <= m; ++i) {
for (int j = 0, siz = vec[i].size(); j < siz; ++j)
if (vec[i][j] > 0) {
if (!f[vec[i][j]]) ++cnt;
++f[vec[i][j]];
} else {
--f[-vec[i][j]];
if (!f[-vec[i][j]]) --cnt;
}
printf("%d\n", cnt);
}
return 0;
}