Universal OJ #637 Solution
闲话
这题非常简单。
题解
将所有的在 \([1,n+1]\) 范围内的数分成两组。一组已经出现过,另一组没有出现过。
考虑将询问离线,按左端点排序。
对于出现过的数 \(x\),其消失的可能性只有一种,那就是所询问区间包含 \(x\) 的所有出现位置且不包含 \(x-1\) 的位置。也就是说,当左端点落在 \(x\) 第一次出现位置前最近的 \(x-1\) 的位置右侧和 \(x\) 第一次出现位置或其左侧时,\(x\) 对答案产生 \(-1\) 的贡献当且仅当右端点落在 \(x\) 最后一次出现位置后最近的 \(x-1\) 位置左侧和 \(x\) 最后一次出现位置及其右侧之间。
对于未出现过的数 \(y\),其出现的可能性同样只有一种,那就是所询问区间包含至少一个 \(y-1\)。当左端点落在任意位置时,\(y\) 对答案产生 \(1\) 的贡献当且仅当右端点落在左端点后最近的 \(y-1\) 位置及其右侧。
扫描线即可。
时间复杂度 \(O((n+m)\log n)\)。
代码
#include <algorithm>
#include <cstdio>
#include <tuple>
#include <utility>
#include <vector>
using namespace std;
const int N = 1e6 + 10;
int tr[N << 2], n, q, cidx, a[N], trs, res[N];
using t3i = tuple<int, int, int>;
using pii = pair<int, int>;
vector<pii> rgs[N];
vector<int> pos[N];
t3i qry[N];
void update(int x, int l, int r, int lb, int rb, int v)
{
if (l >= lb and r <= rb)
{
tr[x] += v;
return;
}
if (tr[x])
{
tr[x << 1] += tr[x], tr[x << 1 | 1] += tr[x];
tr[x] = 0;
}
int mid = (l + r) >> 1;
if (lb <= mid)
update(x << 1, l, mid, lb, rb, v);
if (rb > mid)
update(x << 1 | 1, mid + 1, r, lb, rb, v);
}
int query(int x, int l, int r, int tar)
{
if (l == r)
return tr[x];
if (tr[x])
{
tr[x << 1] += tr[x], tr[x << 1 | 1] += tr[x];
tr[x] = 0;
}
int mid = (l + r) >> 1;
if (tar <= mid)
return query(x << 1, l, mid, tar);
return query(x << 1 | 1, mid + 1, r, tar);
}
int main()
{
scanf("%d%d", &n, &q);
for (int i = 0; i <= n + 1; i++)
{
pos[i].emplace_back(0);
}
for (int i = 1; i <= n; i++)
{
scanf("%d", a + i);
pos[a[i]].emplace_back(i);
}
for (int i = 0; i <= n + 1; i++)
{
pos[i].emplace_back(n + 1);
trs += (pos[i].size() != 2);
}
update(1, 1, n, 1, n, trs);
// fprintf(stderr, "%d\n", trs);
trs = 0;
for (int i = 1; i <= n + 1; i++)
{
if (pos[i].size() > 2) // vanish
{
auto itp = lower_bound(pos[i - 1].begin(), pos[i - 1].end(), pos[i][1]);
if (*itp <= pos[i][pos[i].size() - 2])
continue;
rgs[*prev(itp) + 1].emplace_back(-pos[i][pos[i].size() - 2], -*itp + 1);
if (pos[i][1] + 1 > *itp - 1)
continue;
rgs[pos[i][1] + 1].emplace_back(pos[i][pos[i].size() - 2], *itp - 1);
continue;
}
// generate
if (pos[i - 1].size() == 2)
continue;
rgs[1].emplace_back(pos[i - 1][1], n);
for (int j = 1; j < pos[i - 1].size() - 1; j++)
{
if (pos[i - 1][j] + 1 == pos[i - 1][j + 1])
continue;
rgs[pos[i - 1][j] + 1].emplace_back(-pos[i - 1][j] - 1, -pos[i - 1][j + 1] + 1);
}
}
for (int i = 1; i <= q; i++)
{
auto &[l, r, id] = qry[i];
scanf("%d%d", &l, &r);
id = i;
}
sort(qry + 1, qry + q + 1);
// for (int i = 1; i <= n; i++)
// {
// fprintf(stderr, "t %d %llu\n", i, rgs[i].size());
// for (auto &[l, r] : rgs[i])
// {
// fprintf(stderr, "%d %d\n", l, r);
// }
// }
for (int i = 1; i <= q; i++)
{
auto &[l, r, id] = qry[i];
// fprintf(stderr, "%d %d %d\n", l, r, id);
while (trs < l)
{
trs++;
for (auto &[tl, tr] : rgs[trs])
{
if (tl < 0)
{
update(1, 1, n, -tl, -tr, -1);
continue;
}
update(1, 1, n, tl, tr, 1);
}
}
res[id] = query(1, 1, n, r);
}
for (int i = 1; i <= q; i++)
{
printf("%d\n", res[i]);
}
}

浙公网安备 33010602011771号