BZOJ 4237: 稻草人

4237: 稻草人

Time Limit: 40 Sec  Memory Limit: 256 MB
Submit: 661  Solved: 286
[Submit][Status][Discuss]

Description

JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典。
有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地。和启示中的一样,田地需要满足以下条件:
田地的形状是边平行于坐标轴的长方形;
左下角和右上角各有一个稻草人;
田地的内部(不包括边界)没有稻草人。
给出每个稻草人的坐标,请你求出有多少遵从启示的田地的个数

 

Input

第一行一个正整数N,代表稻草人的个数
接下来N行,第i行(1<=i<=N)包含2个由空格分隔的整数Xi和Yi,表示第i个稻草人的坐标

 

Output

输出一行一个正整数,代表遵从启示的田地的个数

 

Sample Input

4
0 0
2 2
3 4
4 3

Sample Output

3

HINT

 

所有满足要求的田地由下图所示:

 

1<=N<=2*10^5

0<=Xi<=10^9(1<=i<=N)

0<=Yi<=10^9(1<=i<=N)

Xi(1<=i<=N)互不相同。

Yi(1<=i<=N)互不相同。

 

Source

[ Submit][ Status][ Discuss]

 

将y这一维分治一下,每次考虑一个平面,中间割开,下面每个点作为左下点时,上面可以和其配对的右上点的个数。

将所有点按x维排序,扫描线从右向左,上面维护一个单调上升的栈,下面维护一个单调下降的栈,每次拿到下面一个点时,先在下面的栈中二分出第一个y大于它的点,这个点的x坐标是不可逾越的。然后二分出上面栈中有多少个点在这个界限以左,就是这个左下点的合法配对数。

 

UPDATE 2/18 补代码

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 
  5 using namespace std;
  6 
  7 template <class T>
  8 __inline void read(T &x)
  9 {
 10     x = 0;
 11     char c = getchar();
 12     while (c < 48)c = getchar();
 13     while (c > 47)x = x*10 + c - 48, c = getchar();
 14 }
 15 
 16 #define rep(i,x,y) for(register int i=x;i<=y;++i)
 17 #define per(i,x,y) for(register int i=x;i>=y;--i)
 18 
 19 const int mxn = 2E5 + 5;
 20 const int inf = 1E9 + 7;
 21 
 22 int n; long long sum;
 23 
 24 struct pii
 25 {
 26     int x, y;
 27 }p[mxn];
 28 
 29 inline bool cmpX(const pii &a, const pii &b)
 30 {
 31     return a.x < b.x;
 32 }
 33 
 34 inline bool cmpY(const pii &a, const pii &b)
 35 {
 36     return a.y < b.y;
 37 }
 38 
 39 void solve(int l, int r)
 40 {
 41     if (l == r)return;
 42     
 43     int m = (l + r) >> 1;
 44     
 45     nth_element(
 46         p + l,
 47         p + m,
 48         p + r + 1,
 49         cmpY);
 50         
 51     int h = p[m].y;
 52     
 53     solve(l, m);
 54     solve(m + 1, r);
 55     
 56     static pii s[mxn]; 
 57     
 58     int t = 0, a = l, b = m + 1;
 59     
 60     while (a <= m && b <= r)
 61     {
 62         if (p[a].x < p[b].x)
 63             s[t++] = p[a++];
 64         else
 65             s[t++] = p[b++];
 66     }
 67     
 68     while (a <= m)s[t++] = p[a++];
 69     while (b <= r)s[t++] = p[b++];
 70     
 71     memcpy(p + l, s, t * sizeof(pii));
 72     
 73     static pii sa[mxn]; int ta = 0;
 74     static pii sb[mxn]; int tb = 0;
 75     
 76     per (i, r, l)
 77     {
 78         if (p[i].y > h)
 79         {
 80             while (ta && p[i].y < sa[ta].y)--ta; sa[++ta] = p[i];
 81         }
 82         else
 83         {
 84             int ans = 0, lim = p[i].y;
 85             
 86             {
 87                 int lt = 1, rt = tb, mid;
 88                 
 89                 while (lt <= rt)
 90                 {
 91                     mid = (lt + rt) >> 1;
 92                     
 93                     if (sb[mid].y > lim)
 94                         lt = mid + 1, ans = mid;
 95                     else
 96                         rt = mid - 1;
 97                 }
 98             }
 99             
100             if (ans)
101                 lim = sb[ans].x;
102             else
103                 lim = inf;
104                 
105             ans = 0;
106                 
107             {
108                 int lt = 1, rt = ta, mid;
109                 
110                 while (lt <= rt)
111                 {
112                     mid = (lt + rt) >> 1;
113                     
114                     if (sa[mid].x > lim)
115                         lt = mid + 1, ans = mid;
116                     else
117                         rt = mid - 1;
118                 }
119             }
120             
121             sum += ta - ans;
122             
123             while (tb && p[i].y > sb[tb].y)--tb; sb[++tb] = p[i];
124         }
125     }
126 }
127 
128 signed main(void)
129 {
130     read(n);
131     
132     rep (i, 1, n)
133         read(p[i].x),
134         read(p[i].y);
135     
136     sort(p + 1, p + n + 1, cmpX); rep (i, 1, n)p[i].x = i;
137     sort(p + 1, p + n + 1, cmpY); rep (i, 1, n)p[i].y = i;
138     
139     solve(1, n), printf("%lld\n", sum);
140 }

 

@Author: YouSiki

 

转载于:https://www.cnblogs.com/yousiki/p/6412227.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值