链接:点击打开链接
题意:
给你n个数,m个询问(N and M (1 <= N, M <= 50000)),询问包含四个数L,R,A,B 求区间[L,R]里面在区间[A,B]的数的个数。
思路:
首先想到的是而且的树状数组,或者线段树处理,因为数据量太大。但是二维这个维数也不能表示,因为离散化之后50000*50000是不能表示的,那怎么办呢?
划分树,我们只要二分枚举该区间的最小的第几大大于等于A,以及最小的大于B的第几大,然后他们的差值就是个数。时间复杂度为O(nlog(n)*log(n));
这里求区间第几大用到了划分树。
这个是输入的数字是可以重复的。#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define M 50007
#define N 50007
using namespace std;
#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1
struct node{
int l,r;
int mid(){
return (l + r)>>1;
}
}tt[N<<2];
int toLeft[30][N];
int val[30][N],sorted[N];
int n,q,m;
void build(int l,int r,int rt,int d)
{
int i;
tt[rt].l = l;
tt[rt].r = r;
if (l == r)
return ;
int m = tt[rt].mid();
int lsame = m - l + 1;
for (i = l; i <= r; ++i){
if (val[d][i] < sorted[m]) lsame--;
}
int lpos = l;
int rpos = m + 1;
int same = 0;
for (i = l; i <= r; ++i){
if (i == l) toLeft[d][i] = 0;
else toLeft[d][i] = toLeft[d][i - 1];
if (val[d][i] < sorted[m]){
toLeft[d][i]++; val[d + 1][lpos++] = val[d][i];
}
else if (val[d][i] > sorted[m]){
val[d + 1][rpos++] = val[d][i];
}
else{
if (same < lsame){
toLeft[d][i]++;
val[d + 1][lpos++] = val[d][i]; same++;
}
else{
val[d + 1][rpos++] = val[d][i];
}
}
}
build(lc,d + 1);
build(rc,d + 1);
}
int query(int L,int R,int k,int d,int rt){
if (L == R){
return val[d][L];
}
int s = 0; int ss = 0;
if (L == tt[rt].l){
ss = 0; s = toLeft[d][R];
}
else{
ss = toLeft[d][L - 1];
s = toLeft[d][R] - toLeft[d][L - 1];
}
if (k <= s){
int newl = tt[rt].l + ss;
int newr = newl + s - 1;
return query(newl,newr,k,d + 1,rt<<1);
}
else{
int m = tt[rt].mid();
int bb = L - tt[rt].l - ss;
int b = R - L + 1 - s;
int newl = m + bb + 1;
int newr = newl + b - 1;
return query(newl,newr,k - s,d + 1,rt<<1|1);
}
}
int BS1(int L,int R,int l,int r,int A) {
int ans = -1;
while (l <= r) {
int mid = (l + r)>>1;
int res = query(L,R,mid,0,1);
if (res >= A) {
ans = mid; r = mid - 1;
}
else l = mid + 1;
}
return ans;
}
int BS2(int L,int R,int l,int r,int B)
{
int ans = 0;
while (l <= r) {
int mid = (l + r)>>1;
int res = query(L,R,mid,0,1);
if (res > B) { ans = mid; r = mid - 1; }
else l = mid + 1; }
if (ans == 0)
return r;
else return ans - 1;
}
int main() {
int T,i;
int cas = 1;
scanf("%d",&T);
while (T--) {
scanf("%d%d",&n,&m);
for (i = 1; i <= n; ++i) {
scanf("%d",&val[0][i]);
sorted[i] = val[0][i];
}
sort(sorted + 1,sorted + 1 + n);
build(1,n,1,0);
printf("Case #%d:\n",cas++);
int x,y,A,B;
while (m--) {
scanf("%d%d%d%d",&x,&y,&A,&B);
int l = 1; int r = y - x + 1;
int cnt1 = BS1(x,y,l,r,A);
int cnt2 = BS2(x,y,l,r,B);
if (cnt1 == -1) { printf("0\n");
continue; }
printf("%d\n",cnt2 - cnt1 + 1);
}
}
return 0;
}