HDU 1828 Picture(线段树求矩形周长并)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1828

题意:矩形周长并。

思路:节点保存的是一段,这一段的长度以及横向线段的个数。



struct node
{
    int L,R,len,sum,segCount,coverNum;
    int LcoverNum,RcoverNum;
};

struct line
{
    int x,y1,y2,flag;

    line(){}
    line(int _x,int _y1,int _y2,int _flag)
    {
        x=_x;
        y1=_y1;
        y2=_y2;
        flag=_flag;
    }
};

node a[N*3];
line L[N];
int y[N],n,yNum,LNum;


struct pol
{
    int x1,y1,x2,y2;

    void get()
    {
        RD(x1,y1);
        RD(x2,y2);
        if(x1>x2) swap(x1,x2);
        if(y1>y2) swap(y1,y2);
    }
};

pol p[N];

int cmp(line a,line b)
{
    return a.x<b.x;
}

int find(int x)
{
    int low=0,high=yNum-1,mid;
    while(low<=high)
    {
        mid=(low+high)>>1;
        if(y[mid]==x) return mid;
        if(y[mid]>x) high=mid-1;
        else low=mid+1;
    }
}

void build(int t,int L,int R)
{
    a[t].L=L;
    a[t].R=R;
    a[t].coverNum=0;
    a[t].segCount=0;
    a[t].sum=0;
    a[t].LcoverNum=a[t].RcoverNum=0;
    a[t].len=y[R]-y[L];
    if(L+1<R)
    {
        int mid=(L+R)>>1;
        build(t*2,L,mid);
        build(t*2+1,mid,R);
    }
}

void up(int t)
{
    if(a[t].coverNum>0) a[t].sum=a[t].len;
    else if(a[t].L+1<a[t].R) a[t].sum=a[t*2].sum+a[t*2+1].sum;
    else a[t].sum=0;

    if(a[t].coverNum>0)
    {
        a[t].LcoverNum=a[t].RcoverNum=1;
        a[t].segCount=1;
    }
    else if(a[t].L+1<a[t].R)
    {
        a[t].LcoverNum=a[t*2].LcoverNum;
        a[t].RcoverNum=a[t*2+1].RcoverNum;
        a[t].segCount=a[t*2].segCount+a[t*2+1].segCount-a[t*2].RcoverNum*a[t*2+1].LcoverNum;
    }
    else
    {
        a[t].LcoverNum=a[t].RcoverNum=0;
        a[t].segCount=0;
    }
}

void insert(int t,int L,int R,int det)
{
    int mid=(a[t].L+a[t].R)>>1;
    if(a[t].L==L&&a[t].R==R) a[t].coverNum+=det;
    else if(R<=mid) insert(t*2,L,R,det);
    else if(L>=mid) insert(t*2+1,L,R,det);
    else
    {
        insert(t*2,L,mid,det);
        insert(t*2+1,mid,R,det);
    }
    up(t);
}


int cal(pol p[],int n)
{
    LNum=yNum=0;
    int i,x1,y1,x2,y2;
    FOR0(i,n)
    {
        x1=p[i].x1; y1=p[i].y1;
        x2=p[i].x2; y2=p[i].y2;
        L[LNum++]=line(x1,y1,y2,1);
        L[LNum++]=line(x2,y1,y2,-1);
        y[yNum++]=y1;
        y[yNum++]=y2;
    }
    sort(y,y+yNum);
    sort(L,L+LNum,cmp);
    yNum=unique(y,y+yNum)-y;

    build(1,0,yNum-1);
    int ans=0,preLen=0;
    for(i=0;i+1<LNum;i++)
    {
        x1=find(L[i].y1);
        x2=find(L[i].y2);
        insert(1,x1,x2,L[i].flag);
        ans+=2*a[1].segCount*(L[i+1].x-L[i].x);
        ans+=abs(a[1].sum-preLen);
        preLen=a[1].sum;
    }
    insert(1,find(L[i].y1),find(L[i].y2),-1);
    ans+=abs(a[1].sum-preLen);
    return ans;
}

int main()
{
    while(scanf("%d",&n)!=-1)
    {
        int i;
        FOR0(i,n) p[i].get();
        PR(cal(p,n));
    }
    return 0;
}
 
  

  

 
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值