• BZOJ 4237: 稻草人


    4237: 稻草人

    Time Limit: 40 Sec  Memory Limit: 256 MB
    Submit: 661  Solved: 286
    [Submit][Status][Discuss]

    Description

    JOI村有一片荒地,上面竖着N个稻草人,村民们每年多次在稻草人们的周围举行祭典。
    有一次,JOI村的村长听到了稻草人们的启示,计划在荒地中开垦一片田地。和启示中的一样,田地需要满足以下条件:
    田地的形状是边平行于坐标轴的长方形;
    左下角和右上角各有一个稻草人;
    田地的内部(不包括边界)没有稻草人。
    给出每个稻草人的坐标,请你求出有多少遵从启示的田地的个数

    Input

    第一行一个正整数N,代表稻草人的个数
    接下来N行,第i行(1<=i<=N)包含2个由空格分隔的整数Xi和Yi,表示第i个稻草人的坐标

    Output

    输出一行一个正整数,代表遵从启示的田地的个数

    Sample Input

    4
    0 0
    2 2
    3 4
    4 3

    Sample Output

    3

    HINT

    所有满足要求的田地由下图所示:

     

    1<=N<=2*10^5

    0<=Xi<=10^9(1<=i<=N)

    0<=Yi<=10^9(1<=i<=N)

    Xi(1<=i<=N)互不相同。

    Yi(1<=i<=N)互不相同。

    Source

    JOI 2013~2014 春季training合宿 竞技3 By PoPoQQQ

    思(心)考(塞)历程:

    晚上看ysq大佬(%%%)秒切NeighThorn做过的题的时候听到玉环在思考这题...然后NeighThorn和YouSiki果断弃掉NT做过的水题来思考YYH大佬的神题...

    然后两个人对着屏幕和草稿纸陷入了深思...

    一千八百万年之后NT赶脚自己YY出了一个漏洞百出的方法...(真的是漏洞百出...

    感觉我们可以统计每个点对答案的贡献,因为这是个二维的东西,所以可能可以通过分治什么的降到一维...

    我们把所有的点按照x轴坐标排序,然后对y坐标分治,这样我们统计对于上层的每个节点下层有多少个节点可以和其构成合法答案...

    如果下层的点出现了这种情况...显然对于3节点来说1节点是没有用的...

    所以我们对于下层节点维护一个y坐标单调递减的栈,对于上层的每个节点在下层的单调栈里二分答案...

    然后被YouSiki大佬D得很惨...虽然他也被NT卡掉了(hia~hia~hia~...

    然后NT满心欢喜地对YouSiki说:“你去写吧,我懒得写了..."被YouSiki严肃地拒绝了...

    对于一切早已习惯并且淡然了的NT回到电脑屏幕前开始发呆,忽然发现这样是错误的,然后错的还很明显...(所以NT和YouSiki的脑子都锈掉了???

    于是NT和YouSiki再次经过了和平的争吵之后YouSiki童鞋说出了正解...

    我们现在不对上层的每个节点去寻找答案,而是直接计算跨越上下层的合法矩形个数...

    我们对于上层节点维护y坐标单调递增的栈,下层节点维护y坐标单调递减的栈...

    就是酱紫:

    我们枚举上面的点,对于上面的某个点a我们要找到它前面的第一个高度小于它的点来卡住它的下面的点b,就是说下面二分的时候的x坐标是要通过b的x坐标来卡边界的...

    一个分治里面有个二分...时间复杂度$O(nlog^{2}n)$...

    然后NT表示YouSiki太厉害了...然后大爷就又愉快地开始了每天必做功课:催人...

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    //by NeighThorn
    using namespace std;
    
    const int maxn=200000+5;
    
    int n,cnt1,cnt2,top1,top2,mp[2][maxn];
    
    long long ans;
    
    struct M{
    	int x,y;
    	friend bool operator < (M a,M b){
    		return a.x<b.x;
    	}
    }stk[2][maxn],pos[maxn],q[maxn];
    
    inline void CDQ(int l,int r){
    	if(l==r)
    		return;
    	int mid=(l+r)>>1,b1=l,b2=mid+1;
    	for(int i=l;i<=r;i++){
    		if(pos[i].y<=mid)
    			q[b1++]=pos[i];
    		else
    			q[b2++]=pos[i];
    	}
    	memcpy(pos+l,q+l,sizeof(M)*(r-l+1));
    	top1=top2=0;
    	for(int i=l,j=mid+1;j<=r;j++){
    		while(i<=mid&&pos[i].x<pos[j].x){
    			while(top1&&stk[0][top1].y<pos[i].y)
    				top1--;
    			stk[0][++top1]=pos[i];i++;
    		}
    		while(top2&&stk[1][top2].y>pos[j].y)
    			top2--;
    		stk[1][++top2]=pos[j];
    		ans+=top1-(lower_bound(stk[0]+1,stk[0]+top1+1,stk[1][top2-1])-stk[0])+1;
    	}
    	CDQ(l,mid),CDQ(mid+1,r);
    }
    
    signed main(void){
    	scanf("%d",&n);ans=0;
    	for(int i=1;i<=n;i++)
    		scanf("%d%d",&pos[i].x,&pos[i].y),mp[0][i]=pos[i].x,mp[1][i]=pos[i].y;
    	sort(mp[0]+1,mp[0]+n+1);sort(mp[1]+1,mp[1]+n+1);
    	cnt1=unique(mp[0]+1,mp[0]+n+1)-mp[0]-1,cnt2=unique(mp[1]+1,mp[1]+n+1)-mp[1]-1;
    	for(int i=1;i<=n;i++)
    		pos[i].x=lower_bound(mp[0]+1,mp[0]+cnt1+1,pos[i].x)-mp[0],
    		pos[i].y=lower_bound(mp[1]+1,mp[1]+cnt2+1,pos[i].y)-mp[1];
    	sort(pos+1,pos+n+1);CDQ(1,n);
    	printf("%lld
    ",ans);
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    软工作业02
    进行代码复审训练
    源代码管理工具调查
    软工作业PSP与单元测试训练【任务一】
    15软工 15100340
    进行代码复审训练
    源代码管理工具调查
    软工作业PSP与单元测试训练
    软工课后作业001
    20180320作业2:进行代码复审训练
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6412068.html
Copyright © 2020-2023  润新知