[BZOJ2509][主席树]送分题

题意


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


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

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

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

O(n2+n2logn)

轻松rank(倒数)1

#include 
#include 
#include 
#include 
#define N 1010
using 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;
}

你可能感兴趣的:(可持久化数据结构)