BZOJ4237 稻草人(分治+树状数组+单调栈)

  如果要询问的某个纵坐标为inf的点左边是否有点能与其构成所要求的矩形,只要用个单调栈就可以了。可以想到用分治来制造单调性。

  按横坐标排序,每次考虑跨过分治中心的矩形。考虑右边的每个点能与左边的哪些点构成矩形。首先这受到右边点的限制,对于每个点用set求出这个范围。然后对所有点按纵坐标从大到小排序,维护一个树状数组,如果是右边的点直接在树状数组上的该范围查询,左边的点则将其加入单调栈并在树状数组上修改。

  常数过大,在darkbzoj上跑了30s,bzoj上T掉了。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
#define N 200010
#define inf 1000000000
int n,stk[N],b[N],tree[N];
long long ans=0;
struct data{int x,y,d;
}a[N];
set<int> f;
bool cmp(const data&a,const data&b)
{
    return a.x<b.x;
}
bool cmp1(const data&a,const data&b)
{
    return a.y>b.y;
}
void add(int k,int x){while (k<=n+1) tree[k]+=x,k+=k&-k;}
int query(int k){int s=0;while (k) s+=tree[k],k-=k&-k;return s;}
void solve(int l,int r)
{
    if (l==r) return;
    int mid=l+r>>1;
    solve(l,mid);
    solve(mid+1,r);
    for (int i=mid+1;i<=r;i++)
    a[i].d=*f.lower_bound(a[i].y),f.insert(a[i].y);
    for (int i=mid+1;i<=r;i++) f.erase(a[i].y);
    sort(a+l,a+mid+1,cmp1);
    sort(a+mid+1,a+r+1,cmp1);
    int x=l-1,top=0;
    for (int i=mid+1;i<=r;i++)
    {
        while (x<mid&&a[x+1].y>a[i].y)
        {
            x++;
            while (top&&a[x].x>a[stk[top]].x) add(a[stk[top]].y,-1),top--;
            stk[++top]=x;add(a[x].y,1);
        }
        ans+=query(a[i].d)-query(a[i].y);
    }
    x=l-1,top=0;
    for (int i=mid+1;i<=r;i++)
    {
        while (x<mid&&a[x+1].y>a[i].y)
        {
            x++;
            while (top&&a[x].x>a[stk[top]].x) add(a[stk[top]].y,1),top--;
            stk[++top]=x;add(a[x].y,-1);
        }
    }
    sort(a+l,a+mid+1,cmp);
    sort(a+mid+1,a+r+1,cmp);
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4237.in","r",stdin);
    freopen("bzoj4237.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read();
    for (int i=1;i<=n;i++) a[i].x=read(),b[i]=a[i].y=inf-read();
    sort(b+1,b+n+1);
    for (int i=1;i<=n;i++) a[i].y=lower_bound(b+1,b+n+1,a[i].y)-b;
    sort(a+1,a+n+1,cmp);f.insert(n+1);
    solve(1,n);
    cout<<ans;
    return 0;
}

 

posted @ 2018-10-22 19:52  Gloid  阅读(207)  评论(0编辑  收藏  举报