P1502 窗口的星星

第一道扫描线+线段树题。

这道题还耗了我很久的时间,因为不懂得扫描线到底要怎么做而一直翻了很多dalao的题解。

这道题求的是一个指定大小的矩形可以框住多少颗星星,他们的亮度总和最大。

直接移动矩形不可行,我们将每颗星星转换为每颗星星能被矩形框住的响应区域,不难发现也是矩形。

为了不重复计算,我们只考虑在右上区域框住星星,不然会算重。

所以问题成功转换为:求最大的矩形的交,使相应面积最大。

这个时候就可以使用扫描线了。

可以从下往上扫描,每一次记录一个矩形的下边,加入一条线,加上附带的信息比如左右端点和更新答案值。

如何有顺序地扫描?直接用排序排一下就可以了。

思想很容易懂,但是如何使用代码实现?

我们使用一个结构体名字叫line,记录y轴,左右端点和对答案的贡献。

显然碰到矩形的下边,我们对答案就要区间加了,而碰到上边就要区间减了。

最后还要维护全局的最大值,可以直接写一个线段树模板化地维护。

然后还出了个锅:初始化全局任何元素都是0!连build都不用!

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
const int maxn = 100005;
const int INF = 0x3f3f3f3f;
struct Line
{
    int l, r, y, val;
} line[maxn];
int ls[maxn];
int a[maxn], tot;
int n, w, h, ans;
struct segTree
{
    int maxv[maxn << 2], lazy[maxn << 2];
    #define lson (root << 1)
    #define rson (root << 1 | 1)
    void clear()
    {
        memset(maxv, 0, sizeof maxv);
        memset(lazy, 0, sizeof lazy);
    }
    void pushup(int root)
    {
        maxv[root] = std::max(maxv[lson], maxv[rson]);
    }
    /*
    void build(int root, int l, int r)
    {
        if(l == r) maxv[root] = a[l];
        else
        {
            int mid = (l + r) >> 1;
            build(lson, l, mid);
            build(rson, mid + 1, r);
            pushup(root);
        }
    }
    */
    void pushdown(int root, int l, int r)
    {
        if(lazy[root] != 0)
        {
            int &x = lazy[root];
            maxv[lson] += x;
            lazy[lson] += x;
            maxv[rson] += x;
            lazy[rson] += x;
            x = 0;
        }
    }
    void update(int root, int l, int r, int x, int y, int k)
    {
        if(r < x || y < l) return;
        if(x <= l && r <= y)
        {
            maxv[root] += k;
            lazy[root] += k;
            return;
        }
        pushdown(root, l, r);
        int mid = (l + r) >> 1;
        update(lson, l, mid, x, y, k);
        update(rson, mid + 1, r, x, y, k);
        pushup(root);
    }
    int query(int root, int l, int r, int x, int y)
    {
        if(r < x || y < l) return -INF;
        if(x <= l && r <= y) return maxv[root];
        pushdown(root, l, r);
        int mid = (l + r) >> 1;
        return std::max(query(lson, l, mid, x, y), query(rson, mid + 1, r, x, y));
    }
} seg;

bool cmp(Line a, Line b)
{
    if(a.y == b.y) return a.val > b.val;
    return a.y < b.y;
}
int read()
{
    int ans = 0, s = 1;
    char ch = getchar();
    while(ch > '9' || ch < '0'){ if(ch == '-') s = -1; ch = getchar(); }
    while(ch >= '0' && ch <= '9') ans = (ans << 3) + (ans << 1) + ch - '0', ch = getchar();
    return s * ans;
}
void init()
{
    seg.clear();
    memset(line, 0, sizeof line);
    memset(ls, 0, sizeof ls);
    memset(a, 0, sizeof a);
    tot = 0;
    ans = -INF;
}
int main()
{
    int T = read();
    while(T--)
    {
        init();
        n = read(), w = read(), h = read();
        for(int i = 1; i <= n; i++)
        {
            int x = read(), y = read(), bright = read();
            ls[i] = x; ls[i + n] = x + w - 1;
            line[i].l = line[i + n].l = x;
            line[i].r = line[i + n].r = x + w - 1;
            line[i].val = bright; line[i + n].val = -bright;
            line[i].y = y; line[i + n].y = y + h - 1;
        }
        std::sort(ls + 1, ls + n + n + 1);
        a[++tot] = ls[1];
        for(int i = 2; i <= n + n; i++)
        {
            if(ls[i] != ls[i - 1]) a[++tot] = ls[i];
        }
        
        std::sort(line + 1, line + n + n + 1, cmp);
        //seg.build(1, 1, tot);
        for(int i = 1; i <= n + n; i++)
        {
            int l = std::lower_bound(a + 1, a + tot + 1, line[i].l) - a;
            int r = std::lower_bound(a + 1, a + tot + 1, line[i].r) - a;
            seg.update(1, 1, tot, l, r, line[i].val);
            //printf("%d\n", seg.maxv[1]);
            ans = std::max(ans, seg.maxv[1]);
        }
        printf("%d\n", ans);
    }
    return 0;
}
posted @ 2018-10-19 13:09  Garen-Wang  阅读(137)  评论(0编辑  收藏  举报