[BZOJ2509][主席树]送分题

来源:互联网 发布:北京的设计公司知乎 编辑:程序博客网 时间:2024/05/29 05:03

题意


给出平面上的M条平行于坐标轴的线段,问有多少个正方形。


这题其实可以O(n3)暴力10秒卡过去……
对于一个点(x,y),因为线段都是垂直于坐标轴的,我们可以计算出通过它的线段的四个端点。又因为每条线段没有重叠部分,所以可以用类似并查集的方法O(n2)处理出来。

那么暴力就是枚举每个点作为正方形的一个端点,然后枚举正方形的边长再判断。

把平面分成2n条对角线,可以证明每个正方形的两个对角肯定在同一条线段上。
然后对于每条对角线,题目可以转化为有多少对点在彼此的边长范围内。
主席树处理。

O(n2+n2logn)

轻松rank(倒数)1

#include <cstdio>#include <cstring>#include <string>#include <iostream>#define N 1010using namespace std;int n,m,Ans,L[N][N],D[N][N],U[N][N],R[N][N];inline void reaD(int &x){    char Ch=getchar();x=0;    for(;Ch>'9'||Ch<'0';Ch=getchar());    for(;Ch>='0'&&Ch<='9';x=x*10+Ch-'0',Ch=getchar());}int Sl(int x,int y){return L[x][y]<=y?y:L[x][y]=Sl(x,L[x][y]);}int Sd(int x,int y){return D[x][y]<=x?x:D[x][y]=Sd(D[x][y],y);}int Sr(int x,int y){return R[x][y]>=y?y:R[x][y]=Sr(x,R[x][y]);}int Su(int x,int y){return U[x][y]>=x?x:U[x][y]=Su(U[x][y],y);}struct ft{    struct tr{        int l,r,ls,rs,x;    }T[N<<4];    int t,rt[N],tc;    void InserT(int &x,int y,int d){        x=++t;        T[x]=T[y];        T[x].x++;        if(T[x].l==T[x].r) return ;        int mid=T[x].l+T[x].r>>1;        if(d<=mid) InserT(T[x].ls,T[y].ls,d);        else InserT(T[x].rs,T[y].rs,d);    }    int QuerY(int x,int l,int r){        if(T[x].l==l&&T[x].r==r) return T[x].x;        int mid=T[x].l+T[x].r>>1;        if(r<=mid) return QuerY(T[x].ls,l,r);        if(l>mid) return QuerY(T[x].rs,l,r);        return QuerY(T[x].ls,l,mid)+QuerY(T[x].rs,mid+1,r);    }    void build(int &x,int l,int r){        x=++t;        T[x].l=l;T[x].r=r;        if(l==r) return;        int mid=l+r>>1;        build(T[x].ls,l,mid);        build(T[x].rs,mid+1,r);    }    inline void build(){        build(rt[0],1,n+1);        tc=t;    }    inline void clear(){t=tc;}    inline void Insert(int x,int L,int d){        rt[x]=rt[x-1];        if(d>0) InserT(rt[x],rt[x-1],L);    }    inline int Query(int x,int d){return QuerY(rt[x],d,n+1);}}B;inline int calc(int x,int y){    int Res=0;B.clear();    for(int j=1;x<=n;x++,y++,j++){        int k=min(x-U[x][y],y-R[x][y]);        if(k>0)Res+=B.Query(j-1,j)-B.Query(j-k-1,j);        k=min(D[x][y]-x,L[x][y]-y);        B.Insert(j,j+k,k);    }    return Res;}int main(){    memset(L,-1,sizeof(L));    memset(D,-1,sizeof(D));    memset(R,0x7F,sizeof(R));    memset(U,0x7F,sizeof(U));    reaD(n);reaD(m);    for(int i=1,x1,y1,x2,y2;i<=m;i++){        reaD(x1);reaD(y1);        reaD(x2);reaD(y2);        if(x1==x2){            if(y1>y2) swap(y2,y1);            for(int j=y1;j<=y2;j++)L[x1][j]=max(y2,L[x1][j]),R[x1][j]=min(y1,R[x1][j]);        }else{            if(x1>x2) swap(x1,x2);            for(int j=x1;j<=x2;j++)D[j][y1]=max(x2,D[j][y1]),U[j][y1]=min(x1,U[j][y1]);        }    }    for(int i=0;i<=n;i++)        for(int j=0,x,y;j<=n;j++)            Sl(i,j),Sd(i,j),            Sr(i,j),Su(i,j);    B.build();    for(int i=0,x,y,j;i<=n;i++)Ans+=calc(i,0)+calc(0,i+1);    return printf("%d\n",Ans),0;}
0 0