bzoj4237 稻草人——分治

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4237

分治;

先把所有点按 y 排序,然后二分递归;

对于每个 mid ,计算经过它的矩形的个数,把上面的每个点当做右上角,考虑下面多少点可以作为左下角;

上面的限制只有前面的 y 大于等于自己的 y,所以维护递增的单调栈;

下面的限制是后面的 y 小于等于自己的 y,所以维护递减的单调栈;

还要注意 x 的限制,二分找到栈内满足条件的最前面的点,到栈顶的元素个数就是对答案的贡献。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int const maxn=2e5+5;
int n,tpa,tpb,sta[maxn],stb[maxn];
long long ans;
struct N{int x,y;}s[maxn];
bool cmp(N a,N b){return a.y<b.y;}
bool cmpx(N a,N b){return a.x<b.x;}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=((l+r)>>1);
    cdq(l,mid); cdq(mid+1,r);
    sort(s+l,s+mid+1,cmpx); sort(s+mid+1,s+r+1,cmpx);//请不要写成 s+1 
    int p=l; tpa=tpb=0;
    for(int i=mid+1;i<=r;i++)
    {
        while(s[sta[tpa]].y>=s[i].y && tpa)tpa--;
        int pos=s[sta[tpa]].x; sta[++tpa]=i;
        while(p<=mid && s[p].x<s[i].x)
        {
            while(s[stb[tpb]].y<=s[p].y && tpb)tpb--;
            stb[++tpb]=p; p++;
        }
        int L=1,R=tpb,res=-1;
        while(L<=R)
        {
            int Mid=((L+R)>>1);
            if(s[stb[Mid]].x>pos)res=Mid,R=Mid-1;
            else L=Mid+1;
        }
        if(res!=-1)ans+=tpb-res+1;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
        scanf("%d%d",&s[i].x,&s[i].y);
    s[0].x=s[0].y=-1;//
    sort(s+1,s+n+1,cmp);
    cdq(1,n);
    printf("%lld\n",ans);
    return 0;
}

 

posted @ 2018-06-26 21:41  Zinn  阅读(143)  评论(0编辑  收藏  举报