题意本质就是,给定序列,m次询问,每次问[x1,x2]这个区间内的数中,大小位于[y1,y2]这个区间的不同的数有多少个。
求区间不同的数的加强版 。
求区间不同的数的时候,我们只需要维护1个桶,记录每个数出现多少次即可,用一个变量ret保存答案,这里我们需要对每个数都分别保存答案,可以用权值线段树或树状数组维护 。
单点修改,区间查询。
时间复杂度是O(Nsqrt(N)logN) 但是跑不满,因为不一定每次都要修改。
1900ms。
注意我们把y的坐标都加了1,保证树状数组维护的定义域是从1开始。
#include<bits/stdc++.h>
using namespace std;
//#pragma GCC optimize(2)
#define ull unsigned long long
#define ll long long
#define pii pair<int, int>
const int maxn = 1e5 + 10;
const ll mod = 998244353;
const ll inf = (ll)4e17+5;
const int INF = 1e9 + 7;
const double pi = acos(-1.0);
ll inv(ll b){if(b==1)return 1;return(mod-mod/b)*inv(mod%b)%mod;}
inline ll read()
{
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
//平面上若干个点 m次询问 每次问一个矩形内 不同的y坐标有多少个
//莫队 维护树状数组 指针在x轴移动 树状数组维护y轴的桶 表示这个y坐标能否贡献1 每次单点修改 区间查询
int n,c[maxn],m;
int a[maxn];
int ans[maxn];
int num[maxn];//当前区间内 y坐标为i的个数
int block;
struct node
{
int x0,y0,x1,y1;//[x0,x1]区间内 树状数组查[y0,y1]
int id;
}q[maxn];
bool cmp(const node &a,const node &b)
{
return (a.x0/block)^(b.x0/block)?a.x0<b.x0:(((a.x0/block)&1)?a.x1<b.x1:a.x1>b.x1);
}
inline void upd(int x,int val)//更新函数
{
for (; x <= maxn-1; x += (x&-x))//一路找x的父节点,并且更新父节点
{
c[x] += val;
}
}
inline int ask(int x)//查询前缀和
{
int res=0;
for (; x >= 1; x -= (x&-x))
{
res += c[x];
}
return res;
}
inline void add(int x)
{
num[a[x]]++;
if(num[a[x]]==1) upd(a[x],1);
}
inline void del(int x)
{
num[a[x]]--;
if(!num[a[x]]) upd(a[x],-1);
}
void init()
{
memset(c,0,sizeof c);
memset(num,0,sizeof num);
}
int main()
{
int T;cin>>T;
while(T--)
{
init();
scanf("%d %d",&n,&m);
block=sqrt(n);
for(int i=1;i<=n;i++) a[i]=read()+1;
for(int i=1;i<=m;i++)
{
q[i].id=i;
q[i].x0=read();
q[i].y0=read()+1;
q[i].x1=read();
q[i].y1=read()+1;
}
sort(q+1,q+m+1,cmp);
int l=0,r=0;
for(int i=1;i<=m;i++)
{
int ql=q[i].x0,qr=q[i].x1;
while(l<ql) del(l++);
while(l>ql) add(--l);
while(r<qr) add(++r);
while(r>qr) del(r--);
ans[q[i].id]=ask(q[i].y1)-ask(q[i].y0-1);
}
for(int i=1;i<=m;i++) printf("%d\n",ans[i]);
}
return 0;
}