题目链接:点击这里
题目大意:
给定一个长度为
n
n
n 的序列
a
i
a_i
ai ,设二维坐标上的点为
(
i
,
a
i
)
(i,a_i)
(i,ai) ,他们的
x
x
x 左边从
1
n
1~n
1 n ,
y
y
y 轴坐标在
[
0
,
100000
]
[0,100000]
[0,100000] 范围内。给定一个查询矩阵
(
x
0
,
y
0
)
(
x
1
,
y
1
)
(x0,y0) (x1,y1)
(x0,y0)(x1,y1)求在这个矩阵当中有多少个不同的
y
y
y 值大小不同的点
题目分析:
我们可以对问题进行莫队分块,由于莫队对修改需要
O
(
1
)
O(1)
O(1) 来进行操作,所以考虑用分块维护纵坐标:
记一个桶
n
u
m
[
i
]
num[i]
num[i] 表示当前区间纵坐标为
i
i
i 的点有几个,
s
u
m
[
i
]
sum[i]
sum[i] 表示第
i
i
i 个块有几个不同的纵坐标,利用这两个数组可以做到
O
(
1
)
O(1)
O(1) 修改区间加减操作 ,
O
(
n
)
O(\sqrt n)
O(n) 查询区间有多少个不同的数字。
故总时间复杂度为
O
(
n
n
+
m
n
)
O(n\sqrt n+m\sqrt n)
O(nn+mn)
具体细节见代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<set>
#include<unordered_map>
//#define ll long long
#define inf 0x3f3f3f3f
//#define int ll
using namespace std;
inline int read()
{
int res = 0,flag = 1;
char ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch == '-') flag = -1;
ch = getchar();
}
while(ch>='0' && ch<='9')
{
res = (res<<3)+(res<<1)+(ch^48);//res*10+ch-'0';
ch = getchar();
}
return res*flag;
}
const int maxn = 2e5+5;
const int mod = 1e9+7;
const double pi = acos(-1);
const double eps = 1e-8;
int n,m,num[maxn],sum[maxn],f[maxn],ans[maxn],block;
struct query{
int l,r,ll,rr,id;
friend bool operator < (const query &a,const query &b)
{
return (a.l/block)^(b.l/block)?a.l<b.l:(((a.l/block)&1)?a.r<b.r:a.r>b.r);
}
}q[maxn];
void add(int pos)
{
num[pos]++;
if(num[pos] == 1) sum[pos/block]++;
}
void del(int pos)
{
num[pos]--;
if(!num[pos]) sum[pos/block]--;
}
int calc(int pos)
{
int res = 0;
for(int i = 0;i < pos/block;i++) res += sum[i];
for(int i = (pos/block)*block;i <= pos;i++) res += num[i] ? 1 : 0;
return res;
}
signed main()
{
// freopen("1.in","r",stdin);
int t = read();
while(t--)
{
n = read(),m = read(); block = sqrt(n);
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
for(int i = 1;i <= n;i++) f[i] = read();
for(int i = 1;i <= m;i++)
{
q[i].l = read(),q[i].ll = read(),q[i].r = read(),q[i].rr = read(),q[i].id = i;
}
sort(q+1,q+m);
int l = 1,r = 0;
for(int i = 1;i <= m;i++)
{
int ql = q[i].l,qr = q[i].r;
while(l > ql) add(f[--l]);
while(l < ql) del(f[l++]);
while(r > qr) del(f[r--]);
while(r < qr) add(f[++r]);
ans[q[i].id] = calc(q[i].rr)-calc(q[i].ll-1);
}
for(int i = 1;i <= m;i++) printf("%d\n",ans[i]);
}
return 0;
}