zoukankan      html  css  js  c++  java
  • bzoj 4237: 稻草人

    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

    到现在才做稻草人的我...,其实这个题也不算太难,今天考试就是要用这个东西优化dp;

    对于平面点对计数,我们考虑分治,那么我们假设按照y来分治,那么图分为上半部分和下半部分;

    我们只考虑跨过分界线的,同侧的递归处理(注意如果是用cdq处理dp的话,因为右区间要先被左区间更新,再去更新同侧的,所以顺序有点不一样,还要sort);

    那么右上角在上半部分,左下角在下半部分,于是我们枚举右上角;

    对于右上角的限制,只要有一个横坐标小于他且纵坐标小于他的点就不行,于是我们先按照按照横坐标排序,这样我们就能用递增单调栈求出左边第一个小于他的位置;

    然后我们考虑左下角的限制,如果存在一个横坐标大于他且纵坐标大于他的就不合法,我们依然是按照横坐标排序,然后我们相当于是要维护一个递减的单调栈,每个点后面的点就都合法;

    我们需要在下方找到横坐标比右上角限制点大的第一个点,然后从这个点开始往后到栈顶就都是合法的了,这个我们在单调栈中二分,然后直接统计即可;

    具体实现方法就是两个单调栈一起建,然后更新;

    //MADE BY QT666
    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    typedef long long ll;
    const int N=300050;
    struct data{
        int x,y;
    }a[N],b[N];
    int n,tp1,tp2,p[N],q[N];
    ll ans;
    bool cmp(const data &a,const data &b){
        return a.y<b.y;
    };
    int find(int x,int l,int r){
        int ret=r+1;
        while(l<=r){
    	int mid=(l+r)>>1;
    	if(a[q[mid]].x>=x) r=mid-1,ret=mid;
    	else l=mid+1;
        }
        return ret;
    }
    void solve(int l,int r){
        if(l==r) return;
        int mid=(l+r)>>1;
        solve(l,mid);solve(mid+1,r);
        tp1=0;tp2=0;int j=l;
        for(int i=mid+1;i<=r;i++){
    	while(tp1&&a[i].y<a[p[tp1]].y) tp1--;
    	p[++tp1]=i;
    	for(;a[j].x<a[i].x&&j<=mid;j++){
    	    while(tp2&&a[j].y>a[q[tp2]].y) tp2--;
    	    q[++tp2]=j;
    	}
    	ans+=tp2-find(a[p[tp1-1]].x,1,tp2)+1;
        }
        j=l;int k=mid+1;
        for(int i=l;i<=r;i++){
    	if(j<=mid&&(a[j].x<a[k].x||k>r)) b[i]=a[j++];
    	else b[i]=a[k++];
        }
        for(int i=l;i<=r;i++) a[i]=b[i];
    }
    int main(){
        scanf("%d",&n);
        for(int i=1;i<=n;i++) scanf("%d%d",&a[i].x,&a[i].y);
        sort(a+1,a+1+n,cmp);
        solve(1,n);printf("%lld
    ",ans);
        return 0;
    }
    
  • 相关阅读:
    重置mysql数据库密码
    windows下IIS+PHP解决大文件上传500错问题
    ecmobile中IOS版本中界面文字不显示的解决
    linux下重置mysql的root密码
    nginx下rewrite参数超过9个的解决方法
    android模拟器停在Waiting for HOME解决方案
    android模拟器没法通过localhost访问本地服务器的解决
    zend studio导入svn项目后不能代码提示的解决
    排序(1)

  • 原文地址:https://www.cnblogs.com/qt666/p/7695827.html
Copyright © 2011-2022 走看看