题目链接:https://acm.hdu.edu.cn/showproblem.php?pid=6959
题目描述:
您将获得一个数组fx。
对于每个i(1<=i<=n),我们使用XOY坐标平面中的点(i,fx[i])来描述它。
要求您回答m个查询,每个查询中将有一个矩形,您需要计算查询的矩形中有多少不同的y坐标(上面提到的点)。
输入格式:
第一行包含一个整数T(1<=T<=5),表示测试用例的数量。
对于每个测试用例,第一行中有两个整数n,m(1<=n<=100000,1<=m<=100000)。
然后一行包含n个整数fx[i](0<=fx[i]<=100000)
接下来的m行中的每一行都包含四个整数x0,y0,x1,y1(1<=x0<=x1<=n,0<=y0<=y1<=100000),这意味着矩阵的最左下坐标是(x0,y0),最右上坐标是(x1,y1)
输出格式:
每次查询输出一个整数
输入样例:
1
4 2
1 0 3 1
1 0 4 3
1 0 4 2
输出样例:
3
2
题目大意 计算每个矩形中y坐标的种数
思路 用莫队去维护询问的区间,即x坐标,再把y坐标单独拎出来即可
具体代码
#include<bits/stdc++.h>
using namespace std;
const int maxn=1e5+10;
int T,n,m,size,bnum;
int a[maxn],num[maxn],sum[maxn],ans[maxn],belong[maxn];
struct node{
int x1,x2,y1,y2,id;
}q[maxn];
bool cmp(node a,node b){
return (belong[a.x1]^belong[b.x1]) ? belong[a.x1]<belong[b.x1] : ((belong[a.x1]&1) ? a.x2<b.x2 : a.x2>b.x2);
} //如果左端点在不同的区间,则按照左端点从小到大排序;否则如果左端点在同一奇数块就按照右端点的升序排序否,则降序排序
void add(int x){//添加一个数
if(!num[x]++) //如果以前没有这个数就加一
sum[x/size]++;
}
void dec(int x){//删除一个数
if(!--num[x])//如果删掉这个数后,这个数的个数为0,减一
sum[x/size]--;
}
int calc(int x){//前缀和 找y坐标
int now=0;
for(int i=0;i<x/size;i++) now+=sum[i];
for(int i=(x/size)*size;i<=x;i++)
if(num[i]) now+=1;//个数加一
//now+=(num[i]>=1);
return now;
}
int main(){
scanf("%d",&T);
while(T--){
memset(sum,0,sizeof(sum));//初始化
memset(num,0,sizeof(num));
scanf("%d %d",&n,&m);
size=313;//分块
bnum = ceil((double)n/size);//ceil函数是向上取整,它返回的是大于或等于函数的最小整数
for(int i=1;i<=bnum;i++){
for(int j=(i-1)*size+1;j<=i*size;j++){
belong[j]=i;//存每个块的左端点
}
}
for (int i=1;i<=n;i++) scanf("%d",&a[i]);//a[i]相当于y坐标
for (int i=1;i<=m;i++){
scanf("%d %d %d %d",&q[i].x1,&q[i].y1,&q[i].x2,&q[i].y2);
q[i].id=i;//储存下标
}
sort(q+1,q+1+m,cmp); //按照区间排序
int l=1,r=0;
for(int i=1;i<=m;i++){
int ql=q[i].x1,qr=q[i].x2;
while(l<ql) dec(a[l++]);
while(l>ql) add(a[--l]);
while(r<qr) add(a[++r]);
while(r>qr) dec(a[r--]);
ans[q[i].id]=calc(q[i].y2)-calc(q[i].y1-1);//求区间内的y坐标个数
}
for(int i=1;i<=m;i++)
printf("%d\n",ans[i]);
}
return 0;
}