码迷,mamicode.com
首页 > 其他好文 > 详细

bzoj 4237 稻草人

时间:2018-06-26 22:38:40      阅读:222      评论:0      收藏:0      [点我收藏+]

标签:using   else   can   scanf   splay   blank   自己的   一个   long   

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4237

CDQ。然而却不会做。

**分治的话,只要考虑两部分之间对答案的贡献就行了,不用考虑部分内的。

所以就只考虑两部分之间构成的矩形。

考虑枚举上面部分或下面部分的点。不难(?)发现要使用单调栈。因为另一部分的种种限制很符合单调栈的样子。

同时自己枚举的这部分也要弄单调栈。这样就能知道本部分中第一个限制自己的点的位置,进而把这个位置到自己之间的所有另一部分符合要求的点加到答案里。

枚举上面部分的点的话,本部分限制自己的点在自己左边;而枚举下面部分的点的话,本部分限制点在右边,就得从右往左推了,比较不顺。所以枚举上面部分的点吧。

然后另一部分的点只保留在栈里的,二分找到上面部分的限制点(栈里当前点的上一个点)到当前点之间的部分,计入答案。

技术分享图片
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=2e5+5,INF=1e9+5;
int n,stack[N],top;
ll ans;
struct Node{
    int x,y;
    bool operator<(const Node &k)const
        {return x<k.x;}
}a[N];
bool cmp(Node u,Node v){return u.y<v.y;}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=((l+r)>>1);
    cdq(l,mid);cdq(mid+1,r);
    sort(a+l,a+mid+1,cmp);sort(a+mid+1,a+r+1,cmp);
    int k,u=mid+1;
    for(int i=l;i<=mid;i++)
    {    //下面那行导致n^2 
        for(k=i+1;k<=mid&&a[k].x<a[i].x;k++);if(k>mid)k=0;    //故底下赋初值 
        int mn=INF;
        while(a[u].y<a[i].y&&u<r)u++;if(a[u].y<a[i].y)break;
        for(int j=u;j<=r;j++)
        {
            if(a[j].y>a[k].y)break;
            if(a[j].x<mn)ans++,mn=a[j].x;    //故底下赋初值 
        }
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i].y,&a[i].x);//
    sort(a+1,a+n+1);
    a[0].y=INF;a[0].x=INF;cdq(1,n);
    printf("%lld",ans);
    return 0;
}
以为自己写了个nlogn的,其实是n^2logn
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=2e5+5,INF=1e9+5;
int n,stack1[N],top1,stack2[N],top2;
ll ans;
struct Node{
    int x,y;
    bool operator<(const Node &k)const
        {return x<k.x;}
}a[N];
bool cmp(Node u,Node v){return u.y<v.y;}
void cdq(int l,int r)
{
    if(l==r)return;
    int mid=((l+r)>>1);
    cdq(l,mid);cdq(mid+1,r);
    sort(a+l,a+mid+1,cmp);sort(a+mid+1,a+r+1,cmp);
    top1=top2=0;int j=l;
    for(int i=mid+1;i<=r;i++)
    {
        while(top1&&a[stack1[top1]].x>a[i].x)top1--;stack1[++top1]=i;
        for(;j<=mid&&a[j].y<a[i].y;j++)
            {while(top2&&a[stack2[top2]].x<a[j].x)top2--;stack2[++top2]=j;}
        int L=1,R=top2,as=top2+1;    //如果stack2里一个也没有<==>下面的都在当前点的右边 
        while(L<=R)
        {
            int md=((L+R)>>1);    //下面那个是a[stack2[md]]!!!不是a[md]!!! 
            if(a[stack2[md]].y>a[stack1[top1-1]].y)as=md,R=md-1;    //此处需要对a[0].y赋初值 
            else L=md+1;
        }
        ans+=top2-as+1;
    }
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&a[i].y,&a[i].x);//
    sort(a+1,a+n+1);
    a[0].y=-1;cdq(1,n);    //坐标>=0 
    printf("%lld",ans);
    return 0;
}

 

bzoj 4237 稻草人

标签:using   else   can   scanf   splay   blank   自己的   一个   long   

原文地址:https://www.cnblogs.com/Narh/p/9231394.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!