题意:给你一个田地,问左下角和右上角有稻草人并且内部除了边界都没有稻草人的矩形数。
标程:
1 #include<bits/stdc++.h> 2 using namespace std; 3 int read() 4 { 5 int x=0,f=1;char ch=getchar(); 6 while (ch<'0'||ch>'9') {if (ch=='-') f=-1;ch=getchar();} 7 while (ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar(); 8 return x*f; 9 } 10 const int N=200005; 11 int n,q1[N],q2[N]; 12 long long ans; 13 struct node{int x,y;}a[N],tmp[N]; 14 bool cmp(const node &A,const node &B) {return A.y<B.y;} 15 int find(int x,int l,int r) 16 { 17 while (l+1<r) 18 { 19 int mid=(l+r)/2; 20 if (a[q2[mid]].x<x) l=mid;else r=mid;//边界上的点不算 21 } 22 return l; 23 } 24 void solve(int l,int r) 25 { 26 if (l==r) return; 27 int mid=((l+r)>>1); 28 solve(l,mid);solve(mid+1,r); 29 int top1=0,top2=0; 30 for (int i=mid+1,j=l;i<=r;i++) 31 { 32 while (top1&&a[i].y<a[q1[top1]].y) top1--; 33 for (;j<=mid&&a[j].x<a[i].x;j++)//勿取等号,一条线不算矩形 34 { 35 while (top2&&a[j].y>a[q2[top2]].y) top2--; 36 q2[++top2]=j; 37 } 38 ans+=top2-find(a[q1[top1]].x,0,top2+1);//二分边界注意 39 q1[++top1]=i; 40 } 41 int L=l,R=mid+1; 42 for (int i=l;i<=r;i++) 43 if (R>r||a[L].x<a[R].x&&L<=mid) tmp[i]=a[L++];else tmp[i]=a[R++]; 44 for (int i=l;i<=r;i++) a[i]=tmp[i]; 45 } 46 int main() 47 { 48 n=read(); 49 for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read(); 50 sort(a+1,a+n+1,cmp); 51 solve(1,n); 52 printf("%lld ",ans); 53 return 0; 54 }
题解:cdq分治+单调栈+二分
第一感觉李超树也能做吧。维护折点个数。
那么同理上次一道李超树考试题也可以用cdq分治,二分之前预处理前缀和。
将稻草人平面分成上下两块,按照x坐标排序,枚举上部的一个点作为右上角,在下半部分统计有多少个y坐标依次递减的左下角,并且满足比上部离右上角最近的点x坐标更大。上下都用单调栈维护,最后二分可行的左下角。
时间复杂度O(nlog^2(n))。
注意二分的时候边界条件,从0~top2+1。