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; }