P4477 题解
creation_hy · · 题解
再水一篇题解
水题。询问形式容易联想到莫队,让
容易想到容斥。将
然后就很简单了,设
用线段树维护就行了。
时间复杂度
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 6e4 + 5;
const int M = 7e5 + 5;
int n, m, q, lim, a[M], b[N], pos[N], sq, num[N], ans[N];
struct Query
{
int l, r, id;
inline bool operator<(const Query &t) const
{
return num[l] == num[t.l] ? r < t.r : l < t.l;
}
} qy[N];
struct SegTree
{
int tag[M], mx[M];
inline int ls(int p) { return p << 1; }
inline int rs(int p) { return p << 1 | 1; }
inline void push_up(int p) { mx[p] = max(mx[ls(p)], mx[rs(p)]); }
inline void push_down(int p)
{
if (tag[p])
{
tag[ls(p)] += tag[p], tag[rs(p)] += tag[p];
mx[ls(p)] += tag[p], mx[rs(p)] += tag[p];
tag[p] = 0;
}
}
inline void build(int p, int l, int r)
{
if (l == r)
{
mx[p] = l;
return;
}
int mid = l + r >> 1;
build(ls(p), l, mid);
build(rs(p), mid + 1, r);
push_up(p);
}
inline void update(int p, int l, int r, int dl, int dr, int k)
{
if (dl > dr)
return;
if (dl <= l && r <= dr)
{
mx[p] += k, tag[p] += k;
return;
}
push_down(p);
int mid = l + r >> 1;
if (dl <= mid)
update(ls(p), l, mid, dl, dr, k);
if (mid < dr)
update(rs(p), mid + 1, r, dl, dr, k);
push_up(p);
}
} seg;
inline void add(int x) { seg.update(1, 1, n, pos[x], n, -1); }
inline void del(int x) { seg.update(1, 1, n, pos[x], n, 1); }
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> m >> lim, sq = sqrt(m);
for (int i = 1; i <= n; i++)
cin >> a[i], a[i] = lim - a[i];
sort(a + 1, a + 1 + n);
for (int i = 1; i <= m; i++)
{
cin >> b[i], num[i] = (i - 1) / sq + 1;
pos[i] = lower_bound(a + 1, a + 1 + n, b[i]) - a;
}
cin >> q;
for (int i = 1; i <= q; i++)
cin >> qy[i].l >> qy[i].r, qy[i].id = i;
sort(qy + 1, qy + 1 + q);
seg.build(1, 1, n);
for (int i = 1, l = 1, r = 0; i <= q; i++)
{
while (l > qy[i].l)
add(--l);
while (r < qy[i].r)
add(++r);
while (l < qy[i].l)
del(l++);
while (r > qy[i].r)
del(r--);
ans[qy[i].id] = max(0, n - seg.mx[1]);
}
for (int i = 1; i <= q; i++)
cout << ans[i] << '\n';
return 0;
}