稻草人【题解】

前言

网上代码各种各样的都可以AC,但关于判断横(纵)坐标相同是否构成矩形这一点各有不同。实际上,题目数据没有横坐标标或者纵坐标相同的情况,所以放心AC。

sol

CDQ分治都看得出来。反正按纵坐标分为上下两层,然后考虑上对下的贡献。由于不能跨点,研究一个性质放在单调队列里就行了。
比普通分治还是多一个思维.提高组T1难度吧

code

#include<bits/stdc++.h>
#define LL long long
using namespace std;
int N;
template <class T>
inline void read(T&data){
    register char ch=0;data=0;
    while(ch<'0'||ch>'9')ch=getchar();
    while(ch<='9'&&ch>='0'){
        data=(data<<3)+(data<<1)+(ch^48);
        ch=getchar();
    }
}
const int _ = 2e5+1021;
struct poi{
    int x,y;
}p[_],zjy[_];
LL ans=0;int n;
int QL[_],QR[_];
LL tree[_];
bool cmp(register poi a,register poi b){
    return a.y<b.y;
}
bool cmp2(register poi a,register poi b){
    return a.x<b.x;
}
inline int lowbit(register int k){return k&(-k);}
inline void modify(register int loc,register int zh){
    for(register int i=loc;i<=n;i+=lowbit(i))tree[i]+=zh;
}
inline LL query(register int loc1,register int loc2){
    /*--loc1;*/loc1=max(0,loc1);
    register LL ret1=0,ret2=0;
    for(register int i=loc1;i;i-=lowbit(i))ret1+=tree[i];
    for(register int i=loc2;i;i-=lowbit(i))ret2+=tree[i];
    return ret2-ret1;
}
void CDQ(register int L,register int R){
    if(L==R)return;
    register int mid = (L+R)>>1;
    CDQ(L,mid),CDQ(mid+1,R);
    register int pin1=L,pin2=mid+1,ppl=L,lc=0,rc=0;
    for(;pin2<=R;++pin2){
        while(rc&&p[QR [ rc ] ].y >= p[pin2 ].y)--rc;
        QR[++rc]=pin2;
        while(p[pin1].x<=p[pin2].x&&pin1<=mid){
            while(p[pin1].y>p[QL[lc]].y&&lc>0){
                modify(p[QL[lc]].x,-1);--lc;
            }
            QL[++lc]=pin1;modify(p[pin1].x,1);
            zjy[ppl]=p[pin1];
            ++pin1;++ppl;
        }
        zjy[ppl]=p[pin2];++ppl;
        ans+=query(p[QR[rc-1]].x,p[QR[rc]].x);
    }
    while(lc)
        modify(p[QL[lc]].x,-1),--lc;
    while(pin1<=mid){
        zjy[ppl]=p[pin1],++pin1,++ppl;
    }
    for(register int i=L;i<=R;++i)p[i]=zjy[i];
}
int main(){
    read(n);
    for(register int i=1;i<=n;++i){
        read(p[i].x),read(p[i].y);
    }
    sort(p+1,p+n+1,cmp);//横、纵坐标太大了
    for(register int i=1,pre=-1,sum=0;i<=n;++i){
        if(p[i].y==pre)p[i].y=sum;
        else 
            pre=p[i].y,p[i].y=++sum;
    }
    sort(p+1,p+n+1,cmp2);
    for(register int i=1,pre=-1,sum=0;i<=n;++i){
        if(p[i].x==pre)p[i].x=sum;
        else pre=p[i].x,p[i].x=++sum;
        }
    sort(p+1,p+n+1,cmp);
    CDQ(1,n);
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/JH_2002/article/details/81435998