题意:
1~n个数,询问l~r区间,值范围在A~B的个数。
思路:
线段树+离线(肉鸽跟我说的思路,以前真没碰到,线段树的花样太多了),用树状数组替代线段树也可以。
首先先全部接收全部的询问, 然后再把每个询问区间,分为两个区间。例如2-8 -> 1-1和1-8。
然后根据区间右端点从小到大排序,然后边更新线段树边查询,把查询的结果保存起来即可。
code(线段树):
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 50000+5;
typedef long long LL;
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
#define start 1, n, 1
int n, m;
int res[N];
int a[N];
int st[N<<2];
struct Seg {
int l, r, a, b;
int rank;
bool operator < (const Seg &b) const {
return r < b.r;
}
}seg[N<<1];
void update(int l, int r, int rt, int idx) {
if(l == r) {
st[rt]++;
return ;
}
int mid = (l+r)>>1;
if(idx <= mid) update(lson, idx);
else update(rson, idx);
st[rt] = st[rt<<1] + st[rt<<1|1];
}
int query(int l, int r, int rt, int x, int y) {
if(x <= l && y >= r) {
return st[rt];
}
int mid = (l+r)>>1;
int ret = 0;
if(x <= mid) ret += query(lson, x, y);
if(y > mid) ret += query(rson, x, y);
return ret;
}
struct Discretization {
int a[N], n;
void init() {
n = 0;
}
inline void add(int val) {
a[n++] = val;
}
void ok() {
sort(a, a+n);
n = unique(a, a+n)-a;
}
inline int find(int val) {
return lower_bound(a, a+n, val)-a+1;
}
}lsh;
void solve() {
int cnt = 0;
{
int l, r, a, b;
for(int i = 0;i < m; i++) {
scanf("%d%d%d%d", &l, &r, &a, &b);
seg[cnt++] = (Seg){1, r, a, b, i};
if(l != 1) seg[cnt++] = (Seg){1, l-1, a, b, i};
}
}
sort(seg, seg+cnt);
int cur = 0;
for(int i = 0;i < cnt; i++) {
while(cur < seg[i].r) {
cur++;
update(start, lsh.find(a[cur]));
}
int l = lsh.find(seg[i].a), r = lsh.find(seg[i].b);
if(lsh.a[r-1] > seg[i].b) r--;
if(l > r) continue;
int &t = res[seg[i].rank];
t = query(start, l, r) - t;
}
for(int i = 0;i < m; i++) {
printf("%d\n", res[i]);
}
}
int main() {
int T, cas = 0;
scanf("%d", &T);
while(T--) {
printf("Case #%d:\n", ++cas);
scanf("%d%d", &n, &m);
memset(st, 0, sizeof(st));
memset(res, 0, sizeof(res));
lsh.init();
for(int i = 1;i <= n; i++) {
scanf("%d", &a[i]);
lsh.add(a[i]);
}
lsh.ok();
solve();
}
return 0;
}
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 50000+5;
typedef long long LL;
#define lson l, mid, rt<<1
#define rson mid+1, r, rt<<1|1
#define start 1, n, 1
int n, m;
int res[N];
int a[N];
int st[N<<2];
struct PP {
int l, r, val;
}c[int(1e6)];
int cnt;
int head[N];
void update(int l, int r, int &rt, int idx) {
c[++cnt] = c[rt];
c[cnt].val++;
rt = cnt;
if(l == r) return ;
int mid = (l+r)>>1;
if(idx <= mid) update(l, mid, c[rt].l, idx);
else update(mid+1, r, c[rt].r, idx);
}
int query(int l, int r, int rt, int x, int y) {
if(x <= l && y >= r) return c[rt].val;
int ret = 0;
int mid = (l+r)>>1;
if(x <= mid) ret += query(l, mid, c[rt].l, x, y);
if(y > mid) ret += query(mid+1, r, c[rt].r, x, y);
return ret;
}
struct Discretization {
int a[N], n;
void init() {
n = 0;
}
inline void add(int val) {
a[n++] = val;
}
void ok() {
sort(a, a+n);
n = unique(a, a+n)-a;
}
inline int find(int val) {
return lower_bound(a, a+n, val)-a+1;
}
}lsh;
void solve() {
for(int i = 1;i <= n; i++) {
int idx = lsh.find(a[i]);
head[i] = head[i-1];
update(1, lsh.n, head[i], idx);
}
int l, r, a, b;
for(int i = 1;i <= m; i++) {
scanf("%d%d%d%d", &l, &r, &a, &b);
int ll = lsh.find(a), rr = lsh.find(b);
if(lsh.a[rr-1] > b) rr--;
int res = 0;
if(ll <= rr)
res = query(1, lsh.n, head[r], ll, rr) - query(1, lsh.n, head[l-1], ll, rr);
printf("%d\n", res);
}
}
int main() {
int T, cas = 0;
scanf("%d", &T);
while(T--) {
printf("Case #%d:\n", ++cas);
scanf("%d%d", &n, &m);
cnt = 0;
memset(st, 0, sizeof(st));
memset(c, 0, sizeof(c));
memset(head, 0, sizeof(head));
lsh.init();
for(int i = 1;i <= n; i++) {
scanf("%d", &a[i]);
lsh.add(a[i]);
}
lsh.ok();
solve();
}
return 0;
}