• 【BZOJ4237】稻草人


    题意

    给定平面上 (N) 个关键点,询问有多少个矩形满足左下和右上各有一个关键点,且矩形中间没有关键点。

    (Nle 2cdot 10^5) .

    题解

    我们按 (x) 排序分治,对于左右两边的区间按 (y) 排序。

    考虑左边的点对右边的每个点产生的贡献。

    比较容易发现,产生贡献的点的 (x) 一定单减,我们维护一个单调栈。

    我们注意到,如果左边的点能和之前统计的右边的点形成矩形,那么这个点一定不会对当前点产生贡献。

    那么做法就比较显然了:我们对于离当前点最近的横坐标比它小的点,在左边二分找纵坐标比该点小的点数,统计答案时减掉这部分点即可。

    怎么找这样的点?我们对右边维护一个横坐标单增的单调栈即可。

    时间复杂度 (O(nlog ^2 n)) ,代码非常好写。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int gi()
    {
    	char c; int x=0;
    	for(;c<'0'||c>'9';c=getchar());
    	for(;c>='0'&&c<='9';c=getchar())x=(x<<1)+(x<<3)+c-'0';
    	return x;
    }
    const int N=200005;
    struct node {
    	int x,y;
    } a[N],b[N];
    bool operator < (node s, node t) {
    	return s.x<t.x;
    }
    bool cmp(node s, node t) {
    	return s.y<t.y;
    }
    int n,s1[N],s2[N];
    long long ans;
    int _bound(int w, int r)
    {
    	int l=1;
    	while(l<=r)
    	{
    		int mid=l+r>>1;
    		a[s2[mid]].y<w?l=mid+1:r=mid-1;
    	}
    	return l-1;
    }
    void cdq(int l, int r)
    {
    	if(l==r) return ;
    	int mid=l+r>>1;
    	cdq(l,mid),cdq(mid+1,r);
    	int t1=0,t2=0;
    	for(int i=mid+1,j=l;i<=r;++i)
    	{
    		for(;t1&&a[s1[t1]].x>a[i].x;--t1);
    		s1[++t1]=i;
    		for(;j<=mid&&a[j].y<a[i].y;++j)
    		{
    			for(;t2&&a[s2[t2]].x<a[j].x;--t2);
    			s2[++t2]=j;
    		}
    		ans+=t2-_bound(a[s1[t1-1]].y,t2);
    	}
    	merge(a+l,a+mid+1,a+mid+1,a+r+1,b,cmp);
    	for(int i=l,j=0;i<=r;++i,++j) a[i]=b[j];
    }
    int main()
    {
    	n=gi();
    	for(int i=1;i<=n;++i) a[i].x=gi(),a[i].y=gi();
    	sort(a+1,a+1+n);
    	cdq(1,n);
    	printf("%lld",ans);
    }
    
  • 相关阅读:
    mmap文件修改内容的写回
    信号处理之物理信号和软件信号
    从printXX看tty设备(5)串口终端
    从printXX看tty设备(3)键盘输入处理
    LeetCode——Hamming Distance
    LeetCode——Add Strings
    计算树的高度和节点的个数
    LeetCode——Diameter of Binary Tree
    LeetCode——Number of Boomerangs
    九大排序算法总结
  • 原文地址:https://www.cnblogs.com/farway17/p/10747572.html
Copyright © 2020-2023  润新知