zoto HDU6959
题目链接: HDU6959
题目大意:给定\(n\)个位于第一象限的点,\(q\)次询问,每次给出一个矩形范围,求此范围内有多少纵坐标不同的点。
我们可以尝试先考虑一个子问题:在\(y\)轴上某位置加\(1\)并查询前缀中\(1\)的个数,显然我们可以用各种数据结构:线段树,树状数组,分块来解决。解决这个问题后,假如我们矩形框选范围为\((x1,y1) (x2,y2)\)(左下至右上),那么我们只要将 \(\left [ x1,x2 \right ]\) 范围内的点添加,并查询前缀\(y2\)与\(y1-1\)的差即可。
下面的问题便是,我们该如何快速的维护这\(q\)个矩形所覆盖的\(x\)轴上范围。最初在考场上想的线段树套树状数组,但发现我不会写动态开点...而静态数组一定会\(MLE\)。所以这题咕咕咕了,最后发现可以用莫队来维护。
莫队实际上是一种较为优雅的暴力,常规的莫队适用于离线处理多个区间问题,以\(O(1)\)速度从区间\([l,r]\)转移至 \(\left [l,r \right ]\),\([l-1,r]\),\([l,r+1]\),\([l,r-1]\)。复杂度为\(O(n\sqrt{n})\)。\(std\)中使用了莫队套分块,但经过实际测试,莫队套树状数组也可以,但每次操作复杂度变为了\(O(\log_{}{n} )\)级别。
还有一些小细节问题,众所周知,树状数组维护的数据下标只能从\(1\)开始,而给定数组不乏位于\(x\)轴上,所以要将每个涉及\(y\)坐标的数据加\(1\)。此外,我们维护的是区间上不同\(y\)坐标的点,所以要考虑每次转移时转移点的\(y\)坐标的唯一性以及其是否会对答案有贡献,最后就是数据的初始化。
完整代码
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<queue>
#include<stack>
#include<string.h>
#include<cmath>
#include<deque>
#include<vector>
#define Lint long long
using namespace std;
const int N=1e5+10;
struct node{
int xl,yl,xr,yr,id,pos;
};
node a[N];
int T,n,m,Ans[N],f[N],num[N];
int c[N];
int lowbit(int x){
return x&-x;
}
int Sum(int x){//树状数组的求前缀和
int sum=0;
while(x>=1){
sum+=c[x];
x-=lowbit(x);
}
return sum;
}
void add(int x,int y){
while(x<=100002){
c[x]+=y;
x+=lowbit(x);
}
}
bool cmp(node x,node y){
if(x.pos==y.pos){
if(x.pos&1){
return x.xr<y.xr;
}
return x.xr>y.xr;
}
return x.pos<y.pos;
}
void solve(){
memset(num,0,sizeof(num));
memset(c,0,sizeof(c));
scanf("%d%d",&n,&m);
for(int i=1;i<=n;++i){
scanf("%d",&f[i]);
f[i]+=2;
}
int Size=(int)sqrt(n);
for(int i=1;i<=m;++i){
scanf("%d%d%d%d",&a[i].xl,&a[i].yl,&a[i].xr,&a[i].yr);
a[i].yl+=2;
a[i].yr+=2;
a[i].id=i;
a[i].pos=(a[i].xl-1)/Size+1;
}
sort(a+1,a+1+m,cmp);
int XL=a[1].xl,XR=a[1].xr;
for(int i=a[1].xl;i<=a[1].xr;++i){
num[f[i]]++;
if(num[f[i]]==1){
add(f[i],1);
}
}
Ans[a[1].id]=Sum(a[1].yr)-Sum(a[1].yl-1);
for(int i=2;i<=m;++i){
while(XL>a[i].xl){
XL--;
num[f[XL]]++;
if(num[f[XL]]==1){//此次操作改变了此y轴处的唯一性
add(f[XL],1);//树状数组的单点修改
}
}
while(XR<a[i].xr){
XR++;
num[f[XR]]++;
if(num[f[XR]]==1){
add(f[XR],1);
}
}
while(XL<a[i].xl){
num[f[XL]]--;
if(!num[f[XL]]){
add(f[XL],-1);
}
XL++;
}
while(XR>a[i].xr){
num[f[XR]]--;
if(!num[f[XR]]){
add(f[XR],-1);
}
XR--;
}
Ans[a[i].id]=Sum(a[i].yr)-Sum(a[i].yl-1);
}
for(int i=1;i<=m;++i){
printf("%d\n",Ans[i]);
}
}
int main(){
// freopen("1.in","r",stdin);
// freopen("c.out","w",stdout);
scanf("%d",&T);
while(T--){
solve();
}
return 0;
}

浙公网安备 33010602011771号