线段树[扫描线]

20 篇文章 0 订阅
2 篇文章 0 订阅

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


#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn=1000+123;//n=100
struct 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=100
struct 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;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值