2021“MINIEYE杯”中国大学生算法设计超级联赛(1)1010 zoto
https://acm.hdu.edu.cn/contests/contest_showproblem.php?cid=984&pid=1010
题意:
给出二维平面上的若干个点和若干个矩形,查询每个矩形内部有多少个y坐标不一样的点
莫队算法,将矩形按左右边界排序,查询上下边界的y坐标不一样的点
可以用数字证书,也可以继续分块
#include<bits/stdc++.h> using namespace std; #define N 100002 #define lowbit(x) (x&-x) int f[N]; struct node { int l,d,r,u; int id; int ans; int pos; }e[N]; int c[N],sum[N]; int n,m,S; bool cmp(node p,node q) { if(p.pos!=q.pos) return p.pos<q.pos; return p.r<q.r; } bool id(node p,node q) { return p.id<q.id; } void add(int x,int y) { while(x<N) { c[x]+=y; x+=lowbit(x); } } int query(int x) { int cnt=0; while(x) { cnt+=c[x]; x-=lowbit(x); } return cnt; } void update(int x,int k) { x=f[x]; sum[x]+=k; if(k==1 && sum[x]==1) add(x,1); else if(k==-1 && !sum[x]) add(x,-1); } void solve() { int l=1,r=0; for(int i=1;i<=m;i++) { while(l<e[i].l) update(l++,-1); while(l>e[i].l) update(--l,1); while(r<e[i].r) update(++r,1); while(r>e[i].r) update(r--,-1); e[i].ans=query(e[i].u)-query(e[i].d-1); } } int main() { int T; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); memset(c,0,sizeof(c)); memset(sum,0,sizeof(sum)); S=sqrt(n); for(int i=1;i<=n;i++) { scanf("%d",&f[i]); ++f[i]; } for(int i=1;i<=m;i++) { scanf("%d%d%d%d",&e[i].l,&e[i].d,&e[i].r,&e[i].u); e[i].u++; e[i].d++; e[i].id=i; e[i].pos=(e[i].l-1)/S+1; } sort(e+1,e+m+1,cmp); solve(); sort(e+1,e+m+1,id); for(int i=1;i<=m;i++) printf("%d\n",e[i].ans); } }