初涉二维数点问题&&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
",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
",ans[i]);
84     return 0;
85 }
另有关cdq的问题详见「初涉cdq」专题
 
 
 
 
END
 
原文地址:https://www.cnblogs.com/antiquality/p/9028010.html