bzoj 3236 [Ahoi2013]作业 莫队+树状数组
题面
解法
离线询问,然后莫队
建2棵权值树状数组,一棵为区间有多少个数,另一棵为区间有多少个不同的数
在扩展区间的时候用树状数组修改即可
代码
#include <bits/stdc++.h>
#define N 3000010
using namespace std;
template <typename node> void chkmax(node &x, node y) {x = max(x, y);}
template <typename node> void chkmin(node &x, node y) {x = min(x, y);}
template <typename node> void read(node &x) {
x = 0; int f = 1; char c = getchar();
while (!isdigit(c)) {if (c == '-') f = -1; c = getchar();}
while (isdigit(c)) x = x * 10 + c - '0', c = getchar(); x *= f;
}
int n, m, len, a[N], c[N], col[N], cnt[N], ans[N][2];
struct Node {
int l, r, x, y, id;
} b[N];
struct BIT {
int f[N];
int lowbit(int x) {return x & -x;}
void modify(int x, int v) {
for (int i = x; i <= len; i += lowbit(i))
f[i] += v;
}
int query(int x) {
int ret = 0;
for (int i = x; i; i -= lowbit(i))
ret += f[i];
return ret;
}
} T1, T2;
bool cmp(Node a, Node b) {
return col[a.l] == col[b.l] ? a.r < b.r : a.l < b.l;
}
void update(int x, int v) {
cnt[a[x]] += v; T1.modify(a[x], v);
if (v == 1)
if (cnt[a[x]] == 1) T2.modify(a[x], 1);
if (v == -1)
if (!cnt[a[x]]) T2.modify(a[x], -1);
}
main() {
read(n), read(m); len = 0;
for (int i = 1; i <= n; i++)
read(a[i]), c[++len] = a[i];
int siz = (int)sqrt(n);
for (int i = 1; i <= n; i++) col[i] = (i + siz - 1) / siz;
for (int i = 1; i <= m; i++) {
read(b[i].l), read(b[i].r), read(b[i].x), read(b[i].y), b[i].id = i;
c[++len] = b[i].x, c[++len] = b[i].y;
}
sort(c + 1, c + len + 1);
len = unique(c + 1, c + len + 1) - c - 1;
map <int, int> h;
for (int i = 1; i <= len; i++) h[c[i]] = i;
for (int i = 1; i <= n; i++) a[i] = h[a[i]];
for (int i = 1; i <= m; i++)
b[i].x = h[b[i].x], b[i].y = h[b[i].y];
sort(b + 1, b + m + 1, cmp);
for (int i = 1, l = 1, r = 0; i <= m; i++) {
while (r < b[i].r) update(++r, 1);
while (r > b[i].r) update(r--, -1);
while (l < b[i].l) update(l++, -1);
while (l > b[i].l) update(--l, 1);
ans[b[i].id][0] = T1.query(b[i].y) - T1.query(b[i].x - 1);
ans[b[i].id][1] = T2.query(b[i].y) - T2.query(b[i].x - 1);
}
for (int i = 1; i <= m; i++)
cout << ans[i][0] << ' ' << ans[i][1] << "\n";
return 0;
}