JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典。
有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地。和启示中的一样,田地需要满足以下条件:
田地的形状是边平行于坐标轴的长方形;
左下角和右上角各有一个稻草人;
田地的内部(不包括边界)没有稻草人。
给出每个稻草人的坐标,请你求出有多少遵从启示的田地的个数
标签:online page lse mst ref 部分 正整数 const hint
现在
这样的 我们枚举维护上部分
同时维护下部分 下部分x不超过当前上部分的x
比如上图,我们上部分维护到了7
下部分也维护到了6
我们发现4之后的 下部分的栈里面的数 都可以和7组成矩形 且中间没有点
(因为我们维护了下部分递减,所以中间不会再出现比他们小的数,有的话 5也会被弹出栈)
但是4前面的点,和7组成矩形,中间一定会有4,所以是不满足的
所以我们就二分找出第一个x大于的下部分点
ans+=top2-res+1
加上这些点的个数就是答案了
现在我们就解决了 上下组合的问题
剩下的问题继续CDQ分治解决
#include<bits/stdc++.h> using namespace std; const int N=2e5+5; struct node {int x,y;}d[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;} void CDQ(int l,int r) { if(l==r) return ; int mid=(l+r)>>1; top1=top2=0; sort(d+l,d+r+1,cmpy); sort(d+l,d+mid+1,cmpx); sort(d+mid+1,d+r+1,cmpx); int j=l; for(int i=mid+1;i<=r;i++) { while(top1&&d[stack1[top1]].y>=d[i].y) top1--;//上部分维护y递增 stack1[++top1]=i; while(j<=mid&&d[j].x<d[i].x) { while(top2&&d[stack2[top2]].y<=d[j].y) top2--;//下部分维护y递减 stack2[++top2]=j; m j++; } int st=d[stack1[top1-1]].x;//前面一个点的位置 int L=1,R=top2,res=-1; while(L<=R) { int mid=(L+R)>>1; if(d[stack2[mid]].x>st) res=mid,R=mid-1; else L=mid+1; } if(res!=-1) ans+=top2-res+1;//二分出来这个点 后面的点都满足 } CDQ(l,mid);CDQ(mid+1,r); } int main() { freopen("a.in","r",stdin); scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d%d",&d[i].x,&d[i].y); d[0].x=-1;d[0].y=-1; CDQ(1,n); printf("%lld\n",ans); return 0; }
标签:online page lse mst ref 部分 正整数 const hint
原文地址:https://www.cnblogs.com/Heey/p/9021580.html