BZOJ4237 JOISC2014 稻草人 CDQ分治、单调栈

传送门

题意:给出平面上$N$个点,求满足以下两个条件的矩形:①左下角与右上角各有一个点;②矩形内部没有点。$N \leq 2 \times 10^5$,所有数字大于等于$0$,保证坐标两两不同


 最开始想到的是类似于楼房重建的算法,然后打炸了qwq

在多维问题上考虑分治可以降低一维限制,很多时候都会用到(比如三维偏序)。

我们先对$y$值从小到大排序,在分治内部对$x$值从小到大排序,然后考虑左边一半对右边的贡献。

可以知道对于左边一半的两个点$a,b(a<b)$,如果$y_a<y_b$,那么$a$会被$b$阻挡,就不会对答案产生贡献。所以我们可以维护一个$y$值递减的单调栈来保存可能对当前询问的点产生贡献的左边的点的集合,每一次询问下一个点时,把$x$值小于它的其他点加入单调栈即可。

接下来我们考虑右边的点对右边产生的影响(右边的某一些点阻挡了某一些左边的点产生贡献)。发现我们同样可以维护一个$y$值递增的单调栈来保存对当前点有影响的点的集合。每一次我们就取出栈顶的点,在左边的点对应的集合上二分,就可以得到它使多少个左边的点不产生贡献了。

 1 //This code is written by Itst
 2 #include<bits/stdc++.h>
 3 #define BZ
 4 #define mid ((l + r) >> 1)
 5 using namespace std;
 6 
 7 inline int read(){
 8     int a = 0;
 9     bool f = 0;
10     char c = getchar();
11     while(c != EOF && !isdigit(c)){
12         if(c == '-')
13             f = 1;
14         c = getchar();
15     }
16     while(c != EOF && isdigit(c)){
17         a = (a << 3) + (a << 1) + (c ^ '0');
18         c = getchar();
19     }
20     return f ? -a : a;
21 }
22 
23 const int MAXN = 200010;
24 struct node{
25     int x , y;
26 }now[MAXN];
27 int N , hd , Stack[MAXN] , Stack2[MAXN] , top;
28 long long ans;
29 
30 bool cmp1(node a , node b){
31     return a.y < b.y;
32 }
33 
34 bool cmp2(node a , node b){
35     return a.x < b.x;
36 }
37 
38 inline int bis(int x){
39     int L = 0 , R = hd;
40     while(L < R){
41         int m = L + R + 1 >> 1;
42         now[Stack[m]].x < x ? L = m : R = m - 1;
43     }
44     return L;
45 }
46 
47 void solve(int l , int r){
48     if(l == r)
49         return;
50     solve(l , mid);
51     solve(mid + 1 , r);
52     int p1 = l , p2 = mid + 1;
53     hd = top = 0;
54     while(p2 <= r){
55         while(top && now[Stack2[top]].y > now[p2].y)
56             --top;
57         Stack2[++top] = p2;
58         while(p1 <= mid && now[p1].x < now[p2].x){
59             while(hd && now[Stack[hd]].y < now[p1].y)
60                 --hd;
61             Stack[++hd] = p1++;
62         }
63         ans += hd - (top == 1 ? 0 : bis(now[Stack2[top - 1]].x));
64         p2++;
65     }
66     sort(now + l , now + r + 1 , cmp2);
67 }
68 
69 int main(){
70 #ifdef BZ
71     freopen("4237.in" , "r" , stdin);
72     freopen("4237.out" , "w" , stdout);
73 #endif
74     N = read();
75     for(int i = 1 ; i <= N ; i++){
76         now[i].x = read();
77         now[i].y = read();
78     }
79     sort(now + 1 , now + N + 1 , cmp1);
80     solve(1 , N);
81     cout << ans;
82     return 0;
83 }

转载于:https://www.cnblogs.com/Itst/p/9873538.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值