HDU-2461 Rectangles 线段树,矩形面积并

首先申明此方法POJ超时,HDU压线过,优化版见http://www.cnblogs.com/Lyush/archive/2012/07/28/2613516.html

线段树的写法与上面链接中的离散化版本的想法是相近的,只不过这里仅仅是通过线段树来保留某一x区域的多个矩形的面积并。

代码如下:

#include <cstdlib>

#include <cstring>

#include <cstdio>

#include <map>

#include <algorithm>

using namespace std;



int N, M, Q, cnt;



map<int,int>mp;



struct Rectangle

{

    int x1, y1, x2, y2;

}e[25];



struct High

{

    int y;

    bool operator < (High temp) const

    {

        return y < temp.y;

    }

    bool operator == (High temp) const

    {

        return y == temp.y;

    }

}H[50];



struct xLine

{

    int x, y1, y2, sign;

    bool operator < (xLine temp) const

    {

        return x < temp.x;

    }

}Line[50];



struct Node

{

    int l, r, lazy;

}s[200];



void build(int p, int l, int r)

{

    s[p].l = l, s[p].r = r;

    s[p].lazy = 0;  // 初始化为被覆盖了0次

    if (l != r) {

        int mid = (l + r) >> 1;

        build(p<<1, l, mid);

        build(p<<1|1, mid+1, r);

    }

}



void push_up(int p)

{

    

}



void push_down(int p)

{ 

    if (s[p].lazy != 0) {

        s[p<<1].lazy += s[p].lazy;

        s[p<<1|1].lazy += s[p].lazy;

        s[p].lazy = 0;

    }

}



void modify(int p, int l, int r, int val)

{

    if (l == s[p].l && r == s[p].r) {

        s[p].lazy += val;

    }

    else {

        int mid = (s[p].l + s[p].r) >> 1;

        push_down(p);

        if (r <= mid) {

            modify(p<<1, l, r, val);

        }

        else if (l > mid) {

            modify(p<<1|1, l, r, val);

        }

        else {

            modify(p<<1, l, mid, val);

            modify(p<<1|1, mid+1, r, val);

        }

        push_up(p);

    }

}



int query(int p)

{

    if (s[p].l == s[p].r) {

        return (bool)(s[p].lazy) * (H[s[p].r].y - H[s[p].l-1].y);

    }

    else {

        push_down(p);

        return query(p<<1) + query(p<<1|1);

    }

}



int main()

{

    int c, sum, ca = 0;

    while (scanf("%d %d", &N, &M), N|M) {

        for (int i = 1; i <= N; ++i) {

            scanf("%d %d %d %d", &e[i].x1, &e[i].y1, &e[i].x2, &e[i].y2); 

        }

        printf("Case %d:\n", ++ca);

        for (int t = 1; t <= M; ++t) {

            sum = 0; 

            mp.clear();

            scanf("%d", &Q);

            for (int j = 1, k = 0; j <= Q; ++j, k += 2) {

                scanf("%d", &c);

                Line[k].x = e[c].x1, Line[k+1].x = e[c].x2;

                Line[k].sign = 1, Line[k+1].sign = -1;

                // 定义 1为入边,-1为出边

                Line[k].y1 = e[c].y1, Line[k].y2 = e[c].y2;

                Line[k+1].y1 = e[c].y1, Line[k+1].y2 = e[c].y2;

                H[k].y = e[c].y1, H[k+1].y = e[c].y2;

            }

            sort(H, H+2*Q); // 对y轴坐标进行离散话

            cnt = unique(H, H+2*Q) - H; // 去重

            for (int i = 0; i < cnt; ++i) {

                mp[H[i].y] = i;

            }

            sort(Line, Line+2*Q);

            for (int i = 0; i < 2*Q; ++i) {

                Line[i].y1 = mp[Line[i].y1];

                Line[i].y2 = mp[Line[i].y2];

                // 将y坐标进行离散化

            }

            build(1, 0, cnt-1);  // 建立一个空的树来表示整个纵坐标的覆盖情况

            modify(1, Line[0].y1+1, Line[0].y2, Line[0].sign); 

            for (int i = 1; i < (Q << 1); ++i) { // 遍历每一个

                sum += query(1) * (Line[i].x - Line[i-1].x); 

                modify(1, Line[i].y1+1, Line[i].y2, Line[i].sign); 

            }

            printf("Query %d: %d\n", t, sum);

        }

        puts("");

    }

    return 0;

}

你可能感兴趣的:(HDU)