刷题总结——稻草人(bzoj4237cdq分治)

题目:

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)互不相同。

题解:

  首先每次分治前将点按y轴排序,消除y轴的影响,然后分为上下两部分,分别按x轴排序···

  然后用两个单调栈分别维护上部分和下部分,上部分保证y单调递增,下部分保证y单调递减,这样每次将上部分的点作为右上角,找下部分符的点的数量

  由于是按y轴排序且用了单调栈,我们已经排除了y轴的影响,只用找x轴符合情况的点,这时利用我们已经按x轴排的序,直接二分即可

代码:

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<cctype>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
const int N=2e5+5;
struct node
{
  int x,y;
}p[N];
int n,stack1[N],top1,stack2[N],top2;
long long ans=0;
inline bool cmpy(node a,node b)
{
  return a.y<b.y;
}
inline bool cmpx(node a,node b)
{
  return a.x<b.x;
}
inline int R()
{
  char c;int f=0;
  for(c=getchar();c<'0'||c>'9';c=getchar());
  for(;c<='9'&&c>='0';c=getchar())
    f=(f<<3)+(f<<1)+c-'0';
  return f;
}
inline void solve(int l,int r)
{ 
  if(l==r)  return;
  int mid=(l+r)/2;top1=top2=0;
  sort(p+l,p+r+1,cmpy);
  sort(p+l,p+mid+1,cmpx);sort(p+mid+1,p+r+1,cmpx);
  int j=l;
  for(int i=mid+1;i<=r;i++)
  {
    while(top1&&p[stack1[top1]].y>=p[i].y)  top1--;
    stack1[++top1]=i;
    while(j<=mid&&p[j].x<p[i].x)  
    {
      while(top2&&p[stack2[top2]].y<=p[j].y) top2--;
      stack2[++top2]=j;
      j++;
    }
    int st=p[stack1[top1-1]].x;
    int le=1,ri=top2,anss=-1;
    while(le<=ri)
    {
      int mi=(le+ri)/2; 
      if(p[stack2[mi]].x>st)  anss=mi,ri=mi-1;
      else le=mi+1;
    }
    if(anss!=-1)
      ans+=top2-anss+1;
  }
  solve(l,mid),solve(mid+1,r);
}
int main()
{
  //freopen("a.in","r",stdin);
  n=R();
  for(int i=1;i<=n;i++)
    p[i].x=R(),p[i].y=R();
  p[0].x=-1,p[0].y=-1;
  solve(1,n);
  printf("%lld",ans);
  return 0;
}

注意两个细节:

一是每次分治前都要按y轴排序

二是插入一个xy均为-1的点,不然后面二分时会出错

原文地址:https://www.cnblogs.com/AseanA/p/7531698.html