1. 程式人生 > >線段樹(掃描線)掃描線求矩形外邊界周長

線段樹(掃描線)掃描線求矩形外邊界周長

 詳細講解

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=22222;
#define lson i*2,l,m
#define rson i*2+1,m+1,r
int cnt[MAXN*4],suf[MAXN*4],pre[MAXN*4],numseg[MAXN*4],sum[MAXN*4];
struct node
{
    int l,r,h,d;
    node(){}
    node(int a,int b,int c,int d):l(a),r(b),h(c),d(d){}
    bool operator < (const node & b)const
    {
        if (h == b.h) return d > b.d;//這句話不寫也AC,但是還是寫上保險,對於本題來說寫不寫沒區別
        return h<b.h;
    }
}nodes[MAXN];
void PushUp(int i,int l,int r)
{
    if(cnt[i])
    {
        numseg[i]=2;
        pre[i]=suf[i]=1;
        sum[i]=r-l+1;
    }
    else if(l==r)
        numseg[i]=pre[i]=suf[i]=sum[i]=0;
    else
    {
        numseg[i]=numseg[i*2]+numseg[i*2+1];
        if(suf[i*2] && pre[i*2+1]) numseg[i]-=2;
        sum[i]=sum[i*2]+sum[i*2+1];
        pre[i]=pre[i*2];
        suf[i]=suf[i*2+1];
    }
}
void update(int ql,int qr,int v,int i,int l,int r)
{
    if(ql<=l&&r<=qr)
    {
        cnt[i]+=v;
        PushUp(i,l,r);
        return ;
    }
    int m=l+(r-l)/2;//這裡一定小心,如果是m=(l+r)/2,會無限遞迴,棧溢位,如ql=qr=-1且l=-1,r=0的時候
    if(ql<=m) update(ql,qr,v,lson);
    if(m<qr) update(ql,qr,v,rson);
    PushUp(i,l,r);
}
int main()
{
    int t;
    while(scanf("%d",&t)==1)
    {
        int m=0;
        int lbd=10000,rbd=-10000;
        for(int i=1;i<=t;i++)
        {
            int x1,y1,x2,y2;
            scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
            lbd=min(lbd,x1);
            rbd=max(rbd,x2);
            nodes[++m]= node(x1,x2,y1,1);
            nodes[++m]= node(x1,x2,y2,-1);
        }
        sort(nodes+1,nodes+m+1);
        int ans=0,last=0;;
        for(int i=1;i<=m;i++)
        {
            int ql=nodes[i].l;
            int qr=nodes[i].r-1;
            if(ql<=qr)update(ql,qr,nodes[i].d,1,lbd,rbd-1);
            ans += abs(last-sum[1]);
            last=sum[1];
            if(i<m) ans+= numseg[1]*(nodes[i+1].h-nodes[i].h);
        }
        printf("%d\n",ans);
    }
}