线段树[扫描线]

来源:互联网 发布:vim python 环境 编辑:程序博客网 时间:2024/04/29 06:12

hdu1542 Atlantis  POJ 1151(C++才能过, G++WA到死)求矩形面积并


#include <cstdio>#include <cstring>#include <algorithm>using namespace std;const int maxn=1000+123;//n=100struct Segm{    int ymin, ymax;//线段覆盖的区间,当然是离散后的坐标区间    /// 这里保存的是每个值i表示的是i-1到i代表的点之间的距离,因此ymin要+1;    double x;//纪录当前线段在x轴的位置    int s;// 记录当前线段的进出 1  -1    bool operator < (const Segm & a) const    {        return x<a.x;    }}seg[maxn];double T[maxn];//实际覆盖的区域int cover[maxn];// 记录被覆盖的次数double len[maxn];//离散后 线段树节点表示的实际长度int n, M, h;struct Map{    double y;//对y离散    int ind;    bool operator < (const Map & a) const    {        return y<a.y;    }}map[maxn];int bit(int x)/// get highest 1 in bit-number{    if(x==0)return 0;    int n=31;    if((x>>16)==0){n-=16; x<<=16;}    if((x>>24)==0){n-=8; x<<=8;}    if((x>>28)==0){n-=4; x<<=4;}    if((x>>30)==0){n-=2; x<<=2;}    return n-(x>>31);}void init(){    int cnt=0;    for (int i=0; i<n; ++i)    {        scanf("%lf%lf%lf%lf", &seg[i<<1].x, &map[i<<1].y, &seg[i<<1|1].x, &map[i<<1|1].y);        map[i<<1].ind=i<<1; map[i<<1|1].ind=i<<1|1;        seg[i<<1].s=1; seg[i<<1|1].s=-1;    }    sort(map, map+n+n);    for (int i=0; i<n+n; ++i)    {        if(i && map[i].y!=map[i-1].y)            len[cnt++]=map[i].y-map[i-1].y;//这里在区间上直接去重        int num=map[i].ind>>1;        if(map[i].ind&1)            seg[num<<1].ymax=seg[num<<1|1].ymax=cnt-1;        else            seg[num<<1].ymin=seg[num<<1|1].ymin=cnt;    }    sort (seg, seg+n+n);    h=bit(cnt);    M=1<<h;    memset (T, 0, sizeof(T));    memset (cover, 0, sizeof(cover));    for (int i=M+cnt; i>=M; --i)        len[i]=len[i-M];    for (int i=M-1; i>0; --i)        len[i]=len[i<<1]+len[i<<1|1];}void Updata(const int &x){    if(cover[x])T[x]=len[x];    else T[x]=(x>M? 0: T[x<<1]+T[x<<1|1]);}void IU(int l, int r, int v){///不需下传, 因为+1与-1的区间是对称的,有加必有减(不知这样理解对不)    for (l+=M-1, r+=M+1; l^r^1; l>>=1, r>>=1, Updata(l), Updata(r))    {        if(~l&1)cover[l^1]+=v, Updata(l^1);        if( r&1)cover[r^1]+=v, Updata(r^1);    }    while (l>1)    {        l>>=1, r>>=1;        if(l^r)Updata(r);        Updata(l);    }}int main (){    int I=1;    while (scanf("%d", &n), n)    {        init();        n<<=1;        double area=0.;        double now=seg[0].x;        for (int i=0; i<n; ++i)        {//更新区间插入或删除线段, 记录上次的位置            Segm &a = seg[i];            area+=T[1]*(a.x-now);//第一为0            IU(a.ymin, a.ymax, a.s);            now=a.x;        }        printf("Test case #%d\nTotal explored area: %.2lf\n\n", I++, area);    }    return 0;}



hdu 1828 矩形周长

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;#define abs(a) ((a)>0?(a):(-(a)))const int maxn=40000+123;//n=100struct Segm{    int ymin, ymax;//线段覆盖的区间,当然是离散后的坐标区间    /// 这里保存的是每个值i表示的是i-1到i代表的点之间的距离,因此ymin要+1;    int x;//纪录当前线段在x轴的位置    int s;// 记录当前线段的进出 1  -1    bool operator < (const Segm & a) const    {        return x<a.x;    }}seg[maxn];int T[maxn];//实际覆盖的区域int cover[maxn];// 记录被覆盖的次数int len[maxn];//离散后 线段树节点表示的实际长度int point[maxn];bool lc[maxn], rc[maxn];int n, M, h;struct Map{    int y;//对y离散    int ind;    bool operator < (const Map & a) const    {        return y<a.y;    }}map[maxn];int bit(int x)// get highest 1 in bit-number{    if(x==0)return 0;    int n=31;    if((x>>16)==0){n-=16; x<<=16;}    if((x>>24)==0){n-=8; x<<=8;}    if((x>>28)==0){n-=4; x<<=4;}    if((x>>30)==0){n-=2; x<<=2;}    return n-(x>>31);}void init(){    int cnt=0;    for (int i=0; i<n; ++i)    {        scanf("%d%d%d%d", &seg[i<<1].x, &map[i<<1].y, &seg[i<<1|1].x, &map[i<<1|1].y);        map[i<<1].ind=i<<1; map[i<<1|1].ind=i<<1|1;        seg[i<<1].s=1; seg[i<<1|1].s=-1;    }    sort(map, map+n+n);    for (int i=0; i<n+n; ++i)    {        if(i && map[i].y!=map[i-1].y)            len[cnt++]=map[i].y-map[i-1].y;//这里在区间上直接去重        int num=map[i].ind>>1;        if(map[i].ind&1)            seg[num<<1].ymax=seg[num<<1|1].ymax=cnt-1;        else            seg[num<<1].ymin=seg[num<<1|1].ymin=cnt;    }    sort (seg, seg+n+n);    h=bit(cnt);    M=1<<h;    memset (T, 0, sizeof(T));    memset (cover, 0, sizeof(cover));    memset (point, 0, sizeof(point));    memset (lc , 0, sizeof(lc));    memset (rc, 0, sizeof(rc));    for (int i=M+cnt; i>=M; --i)        len[i]=len[i-M];    for (int i=M-1; i>0; --i)        len[i]=len[i<<1]+len[i<<1|1];}void Updata(const int &x){    if(cover[x])    {        T[x]=len[x];        lc[x]=1; rc[x]=1;        point[x]=2;    }    else    {        lc[x]=(x>=M? 0: lc[x<<1]);        rc[x]=(x>=M? 0: rc[x<<1|1]);        point[x]=(x>=M? 0: point[x<<1]+point[x<<1|1]);        if(rc[x<<1] && lc[x<<1|1])point[x]-=2;        T[x]=(x>=M? 0: T[x<<1]+T[x<<1|1]);    }}void IU(int l, int r, int v)/// 下传反而会错的, 改变了区间(秦牛说的){///不需下传, 因为+1与-1的区间是对称的,有加必有减(不知这样理解对不)    for (l+=M-1, r+=M+1; l^r^1; l>>=1, r>>=1, Updata(l), Updata(r))    {        if(~l&1)cover[l^1]+=v, Updata(l^1);        if( r&1)cover[r^1]+=v, Updata(r^1);    }    while (l>1)    {        l>>=1, r>>=1;        if(l^r)Updata(r);        Updata(l);    }}int main (){    int I=1;    while (~scanf("%d", &n))    {        init();        n<<=1;        int  per=0;        int nowx=seg[0].x;        int nowy=0;        for (int i=0; i<n; ++i)        {//更新区间插入或删除线段, 记录上次的位置            Segm &a = seg[i];            per+=point[1]*(a.x-nowx);            //printf("===%d  %lf\n", point[1], a.x-nowx);            IU(a.ymin, a.ymax, a.s);            per+=(abs(T[1]-nowy));//第一为0            //printf("%lf %lf\n", abs(T[1]-nowy), per);            nowx=a.x; nowy=T[1];        }        printf("%d\n", per);    }    return 0;}



原创粉丝点击