初涉二维数点问题&&bzoj1935: [Shoi2007]Tree 园丁的烦恼
离线好评
Description
很久很久以前,在遥远的大陆上有一个美丽的国家。统治着这个美丽国家的国王是一个园艺爱好者,在他的皇家花园里种植着各种奇花异草。有一天国王漫步在花园里,若有所思,他问一个园丁道: “最近我在思索一个问题,如果我们把花坛摆成六个六角形,那么……” “那么本质上它是一个深度优先搜索,陛下”,园丁深深地向国王鞠了一躬。 “嗯……我听说有一种怪物叫九头蛇,它非常贪吃苹果树……” “是的,显然这是一道经典的动态规划题,早在N元4002年我们就已经发现了其中的奥秘了,陛下”。 “该死的,你究竟是什么来头?” “陛下息怒,干我们的这行经常莫名其妙地被问到和OI有关的题目,我也是为了预防万一啊!” 王者的尊严受到了伤害,这是不可容忍的。看来一般的难题是难不倒这位园丁的,国王最后打算用车轮战来消耗他的实力: “年轻人,在我的花园里的每一棵树可以用一个整数坐标来表示,一会儿,我的骑士们会来轮番询问你某一个矩阵内有多少树,如果你不能立即答对,你就准备走人吧!”说完,国王气呼呼地先走了。 这下轮到园丁傻眼了,他没有准备过这样的问题。所幸的是,作为“全国园丁保护联盟”的会长——你,可以成为他的最后一根救命稻草。
Input
第一行有两个整数n,m(0≤n≤500000,1≤m≤500000)。n代表皇家花园的树木的总数,m代表骑士们询问的次数。 文件接下来的n行,每行都有两个整数xi,yi,代表第i棵树的坐标(0≤xi,yi≤10000000)。 文件的最后m行,每行都有四个整数aj,bj,cj,dj,表示第j次询问,其中所问的矩形以(aj,bj)为左下坐标,以(cj,dj)为右上坐标。
Output
共输出m行,每行一个整数,即回答国王以(aj,bj)和(cj,dj)为界的矩形里有多少棵树。
题目分析
这就是一个经典的二维数点问题。
于是这里提供两种做法:
1.树状数组离散化
2.cdq分治
这里是BIT做法:
1 #include<bits/stdc++.h> 2 const int maxn = 500013; 3 4 struct node 5 { 6 int x,y,lb,fr; 7 bool operator < (node a) const 8 { 9 return x==a.x?lb<a.lb:x<a.x; 10 } 11 }f[5*maxn]; 12 int n,m,cnt,tot; 13 int sum[maxn],ans[maxn][5]; 14 int a[maxn],b[maxn],c[maxn],d[maxn],x[maxn],y[maxn],p[5*maxn]; 15 16 int lowbit(int x){return x&-x;} 17 void add(int x){for (; x<=cnt; x+=lowbit(x)) sum[x]++;} 18 int query(int x) 19 { 20 int ret = 0; 21 for (; x; x-=lowbit(x)) 22 ret += sum[x]; 23 return ret; 24 } 25 int read() 26 { 27 char ch = getchar(); 28 int num = 0; 29 for (; !isdigit(ch); ch = getchar()); 30 for (; isdigit(ch); ch = getchar()) 31 num = (num<<1)+(num<<3)+ch-48; 32 return num; 33 } 34 int main() 35 { 36 n = read(), m = read(); 37 for (int i=1; i<=n; i++) 38 x[i] = read()+1, y[i] = read()+1, p[++cnt] = y[i]; 39 for (int i=1; i<=m; i++) 40 a[i] = read()+1, b[i] = read()+1, c[i] = read()+1, d[i] = read()+1, 41 p[++cnt] = b[i], p[++cnt] = d[i]; 42 std::sort(p+1, p+cnt+1); 43 cnt = std::unique(p+1, p+cnt+1)-p-1; 44 for (int i=1; i<=n; i++) 45 y[i] = std::lower_bound(p+1, p+cnt+1, y[i])-p, 46 f[++tot].x = x[i], f[tot].y = y[i]; 47 for (int i=1; i<=m; i++) 48 { 49 b[i] = std::lower_bound(p+1, p+cnt+1, b[i])-p; 50 d[i] = std::lower_bound(p+1, p+cnt+1, d[i])-p; 51 f[++tot].x = a[i]-1, f[tot].y = b[i]-1, f[tot].lb = 1,f[tot].fr = i; 52 f[++tot].x = a[i]-1, f[tot].y = d[i], f[tot].lb = 2,f[tot].fr = i; 53 f[++tot].x = c[i], f[tot].y = b[i]-1, f[tot].lb = 3,f[tot].fr = i; 54 f[++tot].x = c[i], f[tot].y = d[i], f[tot].lb = 4,f[tot].fr = i; 55 } 56 std::sort(f+1, f+1+tot); 57 for (int i=1; i<=tot; i++) 58 if (f[i].lb) ans[f[i].fr][f[i].lb] = query(f[i].y); 59 else add(f[i].y); 60 for (int i=1; i<=m; i++) 61 printf("%d\n",ans[i][4]+ans[i][1]-ans[i][2]-ans[i][3]); 62 return 0; 63 }
这里是cdq做法:
1 #include<bits/stdc++.h> 2 const int maxn = 500013; 3 const int maxk = 10000033; 4 5 struct point 6 { 7 int x,y,lb,mt; 8 point() {} 9 point(int a, int b, int c, int d):x(a),y(b),lb(c),mt(d) {} 10 bool operator < (point a) const 11 { 12 return x==a.x?abs(mt) < abs(a.mt):x < a.x; 13 } 14 }f[maxn*5],s[maxn*5]; 15 int n,m,cnt,dfn,maxy; 16 int sum[maxk],tim[maxk],ans[maxn]; 17 18 int lowbit(int x){return x&-x;} 19 void add(int x) 20 { 21 for (; x <= maxy; x += lowbit(x)) 22 { 23 if (tim[x] != dfn) tim[x] = dfn, sum[x] = 0; 24 sum[x]++; 25 } 26 } 27 int query(int x) 28 { 29 int ret = 0; 30 for (; x; x -= lowbit(x)) 31 if (tim[x] == dfn) 32 ret += sum[x]; 33 return ret; 34 } 35 int read() 36 { 37 char ch = getchar(); 38 int num = 0; 39 for (; !isdigit(ch); ch = getchar()); 40 for (; isdigit(ch); ch = getchar()) 41 num = (num<<1)+(num<<3)+ch-48; 42 return num; 43 } 44 void cdq(int l, int r) 45 { 46 if (l >= r) return; 47 int mid = (l+r)>>1, L = l, R = mid+1, now = l; 48 cdq(l, mid); 49 cdq(mid+1, r); 50 dfn++; 51 while (L <= mid && R <= r) 52 if (f[L] < f[R]){ 53 if (!f[L].mt) add(f[L].y); 54 s[now++] = f[L++]; 55 }else{ 56 if (f[R].mt) ans[f[R].lb] += f[R].mt*query(f[R].y); 57 s[now++] = f[R++]; 58 } 59 while (L <= mid) s[now++] = f[L++]; 60 while (R <= r) 61 { 62 if (f[R].mt) ans[f[R].lb] += f[R].mt*query(f[R].y); 63 s[now++] = f[R++]; 64 } 65 for (int i=l; i<=r; i++) f[i] = s[i]; 66 } 67 int main() 68 { 69 n = read(), m = read(); 70 for (int i=1; i<=n; i++) 71 f[++cnt].x = read()+1, f[cnt].y = read()+1, maxy = std::max(maxy, f[cnt].y); 72 for (int i=1; i<=m; i++) 73 { 74 int a = read()+1, b = read()+1, c = read()+1, d = read()+1; 75 f[++cnt] = point(a-1, b-1, i, 1); 76 f[++cnt] = point(c, d, i, 1); 77 f[++cnt] = point(a-1, d, i, -1); 78 f[++cnt] = point(c, b-1, i, -1); 79 maxy = std::max(maxy, std::max(b, d)); 80 } 81 cdq(1, cnt); 82 for (int i=1; i<=m; i++) 83 printf("%d\n",ans[i]); 84 return 0; 85 }
另有关cdq的问题详见「初涉cdq」专题
END