扫描线(板子向)

原本想虐虐蓝桥寻找一下快感,结果随意选了一道题就是二分+扫描线…于是就滚回去补扫秒线了…(我太菜了)
下面以hdu-1542做例子写的一个板子

扫描线的思想很简单放个图应该就不会忘了:

扫描线(板子向)_第1张图片

扫描线所构造的线段树叶子结点管辖的是一个区间,为了避免以后脑子犯浑,我还是线段树的构造也写一下吧…

把y坐标离散:

int num = 1;
for (int i = 2; i <= n; i++)
{
    if (y[i] == y[i - 1]) continue;
  	y[++num] = y[i];
}

建树:

void build(int l, int r,int now)
{
    tree[now] = node(l, r, 0);
    tree[now].len = y[r] - y[l];
    tree[now].rl = y[l];
    tree[now].rr = y[r];
    tree[now].len = 0;
    if (r == l + 1)
        return;
    int mid = (l + r) >> 1;
    build(l, mid, now << 1);
    build(mid, r, now << 1 | 1);
}

更新:

void pushup(int now)
{
    if (tree[now].flag > 0)
    {
        tree[now].len = tree[now].rr - tree[now].rl;
        return ;
    }
    if (tree[now].l + 1 == tree[now].r) tree[now].len = 0;
    else
        tree[now].len = tree[now << 1].len + tree[now << 1 | 1].len;
}

void update(double l,double r,int v,int now)
{
    if (l <= tree[now].rl && r >= tree[now].rr)
    {
        tree[now].flag += v;
        pushup(now);
        return;
    }
    if (l >= tree[now << 1 | 1].rl)
        update(l, r, v, now << 1 | 1);
    else if (r <= tree[now << 1].rr)
        update(l, r, v, now << 1);
    else
    {
        update(l, r, v, now << 1 | 1);
        update(l, r, v, now << 1);
    }
    pushup(now);
}

getans:

double ans = 0;
for (int i = 1; i < n; i++)
{
 	update(line[i].y1, line[i].y2, line[i].f, 1);
  	ans += (line[i + 1].x - line[i].x) * tree[1].len;
} 

完整代码:(水一下长度我很开心 >_

#include 
#include 
#include 
#include 
#define MAX 100010
using namespace std;

struct node {
    double len;
    double rl, rr;
    int l, r,flag;
    node(int _l = 0, int _r = 0,int _flag=0)
    {
        l = _l; r = _r; flag = _flag;
    }

}tree[MAX];//这里不严谨,因为我MAX习惯的开的太大了...所以这里没有乘4/8

struct Line {
    double x;
    double y1, y2;
    int f;
    Line(double _x = 0, double _y1 = 0, double _y2 = 0, int _f = 0)
    {
        x = _x; y1 = _y1; y2 = _y2; f = _f;
    }

    friend int operator < (Line a,Line b)
    {
        return a.x < b.x;
    }//sort会方便一点,感觉和cmp一样...

}line[300];//开2*n即可

double y[MAX];//同样的2*n

void build(int l, int r,int now)
{
    tree[now] = node(l, r, 0);
    tree[now].len = y[r] - y[l];
    tree[now].rl = y[l];
    tree[now].rr = y[r];
    tree[now].len = 0;
    if (r == l + 1)
        return;
    int mid = (l + r) >> 1;
    build(l, mid, now << 1);
    build(mid, r, now << 1 | 1);
}

void pushup(int now)
{
    if (tree[now].flag > 0)
    {
        tree[now].len = tree[now].rr - tree[now].rl;
        return ;
    }
    if (tree[now].l + 1 == tree[now].r) tree[now].len = 0;
    else
        tree[now].len = tree[now << 1].len + tree[now << 1 | 1].len;
}

void update(double l,double r,int v,int now)
{
    if (l <= tree[now].rl && r >= tree[now].rr)
    {
        tree[now].flag += v;
        pushup(now);
        return;
    }
    if (l >= tree[now << 1 | 1].rl)
        update(l, r, v, now << 1 | 1);
    else if (r <= tree[now << 1].rr)
        update(l, r, v, now << 1);
    else
    {
        update(l, r, v, now << 1 | 1);
        update(l, r, v, now << 1);
    }
    pushup(now);
}


void init()
{
    memset(tree, 0, sizeof(tree));
    memset(y, 0, sizeof(y));
    memset(line, 0, sizeof(line));
}

int main()
{
    int n;
    int len = 1;
    while (cin >> n,n)
    {
        init();
       
        double a, b, c, d;
        for (int i = 1; i <= n; i++)
        {
            cin >> a >> b >> c >> d;
            line[i] = Line(a, b, d, 1);
            line[n+i] = Line(c, b, d, -1);
            y[i] = b; y[i + n] = d;
        }
        n *= 2;
        sort(y + 1, y + n + 1);
        int num = 1;
        for (int i = 2; i <= n; i++)
        {
            if (y[i] == y[i - 1]) continue;
            y[++num] = y[i];
        }
        sort(line + 1, line + n + 1);
        build(1, num, 1);
        double ans = 0;
        for (int i = 1; i < n; i++)
        {
            update(line[i].y1, line[i].y2, line[i].f, 1);
            ans += (line[i + 1].x - line[i].x) * tree[1].len;
        } 
        cout << "Test case #" << len++ << endl;
        cout << "Total explored area: ";
        printf("%.2lf\n\n", ans);
    }

    return 0;
}

你可能感兴趣的:(扫描线(板子向))