题意:在一个给定大小的平面上给出一些不相交的矩形,在这个平面放一个长度为M的线段且不与任何一个矩形相交,有多少种方法。
不失一般性的,可以先求横着放线段的情况。如果枚举放线段的起点的话,那么每个矩形前方m-1长度与自己等宽的区域也是不能放置起点的,那么除去所有不能放置起点的区域,其余区域的面积就是横着放线段的方案数。竖着放同理。
求面积,上模板,线段树求矩形并的面积。
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <map>
#define ls(x) (x << 1)
#define rs(x) ((x << 1) + 1)
using namespace std;
const int maxn = 100000 + 100;
int w, h, n, m, tot;
map<int, int> mm;
int num[maxn];
struct rec
{
int x1, x2, y1, y2;
}mac[maxn];
struct line
{
int a, b, c;
int flag;
bool operator < (const line & rhs) const
{
return c < rhs.c;
}
}lines[maxn];
struct seg_tree
{
int l[5 * maxn], r[5 * maxn];
int c[5 * maxn];
int ans[5 * maxn];
void build(int pos, int le, int ri)
{
l[pos] = le; r[pos] = ri;
c[pos] = 0;
ans[pos] = num[ri] - num[le];
if(ri - le > 1)
{
int mid = (le + ri) / 2;
build(ls(pos), le, mid);
build(rs(pos), mid, ri);
}
}
void update(int pos)
{
if(c[pos] > 0) ans[pos] = 0;
else if(r[pos] - l[pos] == 1) ans[pos] = num[r[pos]] - num[l[pos]];
else ans[pos] = ans[ls(pos)] + ans[rs(pos)];
}
void add(int pos, int le, int ri, int flag)
{
if(le <= l[pos] && ri >= r[pos])
{
if(flag) c[pos]++;
else c[pos]--;
}
else
{
int mid = (l[pos] + r[pos]) / 2;
if(ri > mid) add(rs(pos), le, ri, flag);
if(le < mid) add(ls(pos), le, ri, flag);
}
update(pos);
}
}tree;
void prework()
{
for(int i = 0; i < n; ++i)
{
scanf("%d %d %d %d", &mac[i].x1, &mac[i].y1, &mac[i].x2, &mac[i].y2);
}
}
void solve()
{
long long ans = 0;
mm.clear(); mm[1] = 0; mm[h + 1] = 0; mm[h - m + 2] = 0;
for(int i = 0; i < n; ++i)
{
int tmp = (mac[i].y1 - (m - 1)) > 1 ? mac[i].y1 - (m - 1) : 1;
lines[i].a = lines[i + n].a = tmp;
lines[i].b = lines[i + n].b = mac[i].y2 + 1;
lines[i].c = mac[i].x1; lines[i + n].c = mac[i].x2 + 1;
lines[i].flag = 1; lines[i + n].flag = 0;
mm[lines[i].a] = 0; mm[lines[i].b] = 0;
}
tot = 0;
for(map<int, int>::iterator it = mm.begin(); it != mm.end(); ++it)
{
it->second = ++tot;
num[tot] = it->first;
}
sort(lines, lines + 2 * n);
tree.build(1, 1, tot);
if(m != 1) tree.add(1, mm[h - m + 2], mm[h + 1], 1);
int sl = 1;
for(int i = 0; i < 2 * n; ++i)
{
ans += (long long)(lines[i].c - sl) * tree.ans[1];
tree.add(1, mm[lines[i].a], mm[lines[i].b], lines[i].flag);
sl = lines[i].c;
}
ans += (long long)((w + 1) - sl) * tree.ans[1];
mm.clear(); mm[1] = 0; mm[w + 1] = 0; mm[w - m + 2] = 0;
for(int i = 0; i < n; ++i)
{
int tmp = (mac[i].x1 - (m - 1) > 1) ? mac[i].x1 - (m - 1) : 1;
lines[i].a = lines[i + n].a = tmp;
lines[i].b = lines[i + n].b = mac[i].x2 + 1;
lines[i].c = mac[i].y1; lines[i + n].c = mac[i].y2 + 1;
lines[i].flag = 1; lines[i + n].flag = 0;
mm[lines[i].a] = 0; mm[lines[i].b] = 0;
}
tot = 0;
for(map<int, int>::iterator it = mm.begin(); it != mm.end(); ++it)
{
it->second = ++tot;
num[tot] = it->first;
}
sort(lines, lines + 2 * n);
tree.build(1, 1, tot);
if(m != 1) tree.add(1, mm[w - m + 2], mm[w + 1], 1);
sl = 1;
for(int i = 0; i < 2 * n; ++i)
{
ans += (long long)(lines[i].c - sl) * tree.ans[1];
tree.add(1, mm[lines[i].a], mm[lines[i].b], lines[i].flag);
sl = lines[i].c;
}
ans += (long long)((h + 1) - sl) * tree.ans[1];
if(m == 1) ans /= 2;
cout << ans << "\n";
}
int main()
{
freopen("in.txt", "r", stdin);
while(~scanf("%d %d %d %d", &w, &h, &n, &m))
{
prework();
solve();
}
return 0;
}