AcWing 1228. 油漆面积(线段树)

貌似某一届蓝桥省A赛的压轴题,
Problem
去年的这个时间发过这个问题,当时还庆幸省A的题目这么简单,当时的解答是暴力解法,这个题现场比赛能AC的都是大佬了,难度还是比较高的。
去年的题解
网上普遍都是暴力求解的,由于蓝桥的OJ并没有给出满数据的测试,所以暴力也能过,但是其实数据量达到5000就已经超时了,暴力简单,但是这个题的优化是很难的,需要用线段树优化,而且是一个很难想到,不常见的线段树做法。

这个题太难想了,需要一个线段树的结构加上一个线段结构,线段树的结构除了左右端点再加cnt表示当前区间被覆盖的次数,len表示当前区间至少被覆盖一次的长度(最大覆盖长度),构建线段树也是比较奇怪,是竖着构建的,具体看图。
传上去感觉有点简陋了,红色框框是给出的面积(蓝色的矩形一样。。)

在这里插入图片描述
接下来就是计算了,比较繁琐,主要是计算和线段树模板。
这边给出Cpp和Java代码,语言并不重要

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

using namespace std;

const int N = 10010;

int n;
struct Segment
{
    int x, y1, y2;
    int k;
    bool operator< (const Segment &t)const
    {
        return x < t.x;
    }
}seg[N * 2];
struct Node
{
    int l, r;
    int cnt, len;
}tr[N * 4];

void pushup(int u)
{
    if (tr[u].cnt > 0) tr[u].len = tr[u].r - tr[u].l + 1;
    else if (tr[u].l == tr[u].r) tr[u].len = 0;
    else tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;
}

void build(int u, int l, int r)
{
    tr[u] = {l, r};
    if (l == r) return;
    int mid = l + r >> 1;
    build(u << 1, l, mid), build(u << 1 | 1, mid + 1, r);
}

void modify(int u, int l, int r, int k)
{
    if (tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].cnt += k;
        pushup(u);
    }
    else
    {
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u << 1, l, r, k);
        if (r > mid) modify(u << 1 | 1, l, r, k);
        pushup(u);
    }
}

int main()
{
    scanf("%d", &n);
    int m = 0;
    for (int i = 0; i < n; i ++ )
    {
        int x1, y1, x2, y2;
        scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
        seg[m ++ ] = {x1, y1, y2, 1};
        seg[m ++ ] = {x2, y1, y2, -1};
    }

    sort(seg, seg + m);

    build(1, 0, 10000);

    int res = 0;
    for (int i = 0; i < m; i ++ )
    {
        if (i > 0) res += tr[1].len * (seg[i].x - seg[i - 1].x);
        modify(1, seg[i].y1, seg[i].y2 - 1, seg[i].k);
    }

    printf("%d\n", res);

    return 0;
}
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Arrays;

class Main {
    static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    static PrintWriter pw = new PrintWriter(System.out);
    static int N = 10010, n;
    static Node node[] = new Node[N * 4];
    static Seg seg[] = new Seg[N * 2];

    public static void main(String[] args) throws IOException {
        n = Integer.parseInt(br.readLine());
        int m = 0;
        for (int i = 0; i < n; i++) {
            String s[] = br.readLine().split(" ");
            int x1 = Integer.parseInt(s[0]);
            int y1 = Integer.parseInt(s[1]);
            int x2 = Integer.parseInt(s[2]);
            int y2 = Integer.parseInt(s[3]);
            seg[m++] = new Seg(x1, y1, y2, 1);
            seg[m++] = new Seg(x2, y1, y2, -1);
        }
        Arrays.sort(seg, 0, m);
        build(1, 0, 10000);

        int res = 0;
        for (int i = 0; i < m; i++) {
            if (i > 0) res += node[1].len * (seg[i].x - seg[i - 1].x);
            modify(1, seg[i].y1, seg[i].y2 - 1, seg[i].k);
        }
        pw.print(res);
        pw.flush();
        pw.close();
        br.close();
    }

    public static void pushup(int x) {
        if (node[x].cnt > 0) node[x].len = node[x].r - node[x].l + 1;
        else if (node[x].l == node[x].r) node[x].len = 0;
        else node[x].len = node[x << 1].len + node[x << 1 | 1].len;
    }

    public static void build(int u, int l, int r) {
        node[u] = new Node(l, r);
        if (l == r) return;
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
    }

    public static void modify(int u, int l, int r, int k) {
        if (node[u].l >= l && node[u].r <= r) {
            node[u].cnt += k;
        } else {
            int mid = node[u].l + node[u].r >> 1;
            if (l <= mid) modify(u << 1, l, r, k);
            if (r > mid) modify(u << 1 | 1, l, r, k);
        }
        pushup(u);
    }

}

class Node {
    int l, r;
    int cnt, len;

    public Node(int l, int r) {
        this.l = l;
        this.r = r;
    }
}

class Seg implements Comparable<Seg> {
    int x, y1, y2, k;

    public Seg(int x, int y1, int y2, int k) {
        this.x = x;
        this.y1 = y1;
        this.y2 = y2;
        this.k = k;
    }

    @Override
    public int compareTo(Seg seg) {
        return this.x - seg.x;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值