貌似某一届蓝桥省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;
}
}
orz