hdu 1828、poj1177求矩形周长并 线段树 扫描线

来源:互联网 发布:js电子相册 编辑:程序博客网 时间:2024/05/05 20:21

hdu 1828 http://acm.hdu.edu.cn/showproblem.php?pid=1828

poj 1177 http://poj.org/problem?id=1177

 

 

 

#include <iostream>#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn= 5010;struct node{    int lef, rig, mid, cov;}seg[8*maxn];struct point{    int lef, rig, pos, flag;    //flag为1, 下边, flag为-1 上边}px[2*maxn], py[2*maxn];     // px 为对y做线段树, py为对x做线段树int disx[2*maxn], disy[2*maxn];     //离散坐标, 下标为离散值int n, lenx, leny;            //横纵坐标离散后长度__int64 ans;void init(){    int i, j, k, x1, y1, x2, y2;    for( i=0; i<n; i++){        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);        px[i*2+1].lef= px[i*2].lef= y1;        px[i*2+1].rig= px[i*2].rig= y2;        px[i*2].pos= x1;        px[i*2].flag= 1;        px[i*2+1].pos= x2;        px[i*2+1].flag= -1;        py[i*2+1].lef= py[i*2].lef= x1;        py[i*2+1].rig= py[i*2].rig= x2;        py[i*2].pos= y1;        py[i*2].flag= 1;        py[i*2+1].pos= y2;        py[i*2+1].flag= -1;        disx[i*2]= x1;        disx[i*2+1]= x2;        disy[i*2]= y1;        disy[i*2+1]= y2;    }}bool cmp( point x, point y){    return x.pos < y.pos;}void disperse(){    sort( disx, disx+ 2*n);    sort( disy, disy+ 2*n);    lenx= unique(disx, disx+ 2*n)- disx;    leny= unique(disy, disy+ 2*n)- disy;    sort( px, px+ 2*n, cmp);     //对y做线段树,按pos(即x)顺序由小及大排列    sort( py, py+ 2*n, cmp);}void maketree( int num, int lef, int rig){    seg[num].lef= lef;    seg[num].rig= rig;    seg[num].mid= (lef + rig) >> 1;    seg[num].cov= 0;    if( lef +1!= rig){        maketree( num*2, lef, seg[num].mid);        maketree( num*2+ 1, seg[num].mid, rig);    }}//1. 当seg[num].cov由0变1时,记录线段长度,并乘2,即上下对应两边长度和//2. 对于seg[num].cov== 0且 左右点相符, 同时为新加线段,而非已有线段向下更新时,计起长度//3. 若左右端点相符,且seg[num].cov>0时, seg[num].cov+= cov//4. 若左右端点相符,seg[num].cov==0,并且为已有线段向下更新,而非新加入线段,seg[num].cov+= cov//5. 对于某条seg[num].cov>0的线段,若要更新其一部分,即子线段,则先把这条线段的//   seg[num].cov更新到其所有子节点,再把seg[num].cov赋为-1, 再对其子线段进行更新//6. tt 为1时,为新加线段,tt为0时,是已有线段向下更新//7. tmp为1,对y建的线段树,tmp为0, 对x建的线段树//8. 已经标记为-1的线段,不会再变为其他值int insert( int num, int lef, int rig, int cov, int tt, int tmp){    if( seg[num].cov == 0 && seg[num].lef== lef && seg[num].rig== rig  && tt== 1){        seg[num].cov= 1;        if( tmp== 1)return disy[rig]- disy[lef];        else return disx[rig]-disx[lef];    }    if( seg[num].cov >= 0 && seg[num].lef == lef && seg[num].rig== rig){        seg[num].cov+= cov;        return 0;    }    if( seg[num].cov > 0){        insert( num*2, seg[num].lef, seg[num].mid, seg[num].cov, 0, tmp);        insert( num*2+1, seg[num].mid, seg[num].rig, seg[num].cov, 0,  tmp);    }    seg[num].cov= -1;    if( rig <= seg[num].mid)        return insert( num*2, lef, rig, cov, tt, tmp);    else if( lef >= seg[num].mid)        return insert( num*2+1, lef, rig, cov, tt, tmp);    else return insert( num*2, lef, seg[num].mid, cov, tt, tmp) + insert( num*2+1, seg[num].mid, rig, cov, tt, tmp);}int bx(int x){   //查找x的离散后坐标    int lef= 0, rig= lenx-1, mid;    while( lef <= rig){        mid= (lef + rig) >> 1;        if( disx[mid] < x) lef= mid+1;        else if( disx[mid] > x) rig= mid- 1;        else return mid;    }}int by(int y){    int lef= 0, rig= leny-1, mid;    while( lef <= rig){        mid= (lef + rig) >> 1;        if( disy[mid] < y) lef= mid+1;        else if( disy[mid] > y) rig= mid- 1;        else return mid;    }}int main(){   // freopen("1.txt", "r", stdin);    int i, aa;    while( scanf("%d", &n) != EOF){        init();        disperse();        ans= 0;        //分别对对x、y 扫描线, 求长度并        maketree(1, 0, leny);        for( i=0; i<2*n; i++){            ans+= insert(1,  by(px[i].lef), by(px[i].rig), px[i].flag, 1,  1);        }        maketree(1, 0, lenx);        for( i=0; i<2*n; i++){            ans+= insert(1,  bx(py[i].lef), bx(py[i].rig), py[i].flag, 1, 0);        }        printf("%d\n", ans*2);    }    return 0;}


 

原创粉丝点击