using namespace std;
#define int long long
using ll = long long;
template<typename T = long long>
struct RectUnion {
struct Event {
T x, y1, y2;
int mark;
bool operator<(const Event& o) const { return x < o.x; }
};
struct SegTree {
int n;
vector<T> ys;
vector<int> cnt;
vector<T> len;
SegTree(vector<T> coords) {
sort(coords.begin(), coords.end());
coords.erase(unique(coords.begin(), coords.end()), coords.end());
ys = coords;
n = (int)ys.size() - 1;
if (n < 1) n = 1;
cnt.resize(n << 2);
len.resize(n << 2);
}
inline T segLen(int l, int r) { // 第l个区间到第r个区间的总长度
return ys[r + 1] - ys[l];
}
void pull(int p, int l, int r) {
if (cnt[p]) len[p] = segLen(l, r);
else if (l == r) len[p] = 0;
else len[p] = len[p<<1] + len[p<<1|1];
}
void upd(int p, int l, int r, int L, int R, int v) {
if (L > r || R < l) return;
if (L <= l && r <= R) {
cnt[p] += v;
pull(p, l, r);
return;
}
int mid = (l + r) >> 1;
upd(p<<1, l, mid, L, R, v);
upd(p<<1|1, mid+1, r, L, R, v);
pull(p, l, r);
}
// 对外接口:在[y1,y2]闭区间更新(内部自动转开区间处理)
void update(T y1, T y2, int v) {
int L = lower_bound(ys.begin(), ys.end(), y1) - ys.begin();
int R = lower_bound(ys.begin(), ys.end(), y2) - ys.begin();
// 转成开区间下标:闭区间[y1,y2]对应开区间[y1, y2+ε)
// 在离散化数组中就是找y2的下一个位置
// 但这里我们直接用:闭区间[l,r]对应线段树区间[l, r-1](因为ys[r]是右端点)
// 实际上:y2对应下标pos,则区间[pos, next) 要包含y2这个点,需要到pos
// 简化:用户传闭区间,我们内部转 [y1, y2+1) 如果坐标是整数且单位长度
// 通用做法:找到y2的位置,然后-1作为右边界(因为ys[i]到ys[i+1]是一个区间)
R--; // 关键:y2是右端点,对应线段树区间要-1
if (L <= R) upd(1, 0, n-1, L, R, v);
}
T query() { return len[1]; }
};
vector<Event> e;
bool built = false;
// 用户友好接口:添加闭区间矩形 [x1,x2] × [y1,y2]
void add(T x1, T y1, T x2, T y2) {
// 内部自动转开区间:[x1, x2+1) × [y1, y2+1)
// 适用于整数坐标,单位格子的情况
e.push_back({x1, y1, y2 + 1, 1});
e.push_back({x2 + 1, y1, y2 + 1, -1});
built = false;
}
// 如果用户明确要开区间,提供raw接口
void addRaw(T x1, T y1, T x2, T y2) {
e.push_back({x1, y1, y2, 1});
e.push_back({x2, y1, y2, -1});
built = false;
}
T solve() {
if (e.empty()) return 0;
// 收集y坐标(已经是开区间的y2了)
vector<T> ys;
for (auto& ev : e) {
ys.push_back(ev.y1);
ys.push_back(ev.y2);
}
SegTree st(ys);
sort(e.begin(), e.end());
T res = 0, lastX = e[0].x;
for (size_t i = 0; i < e.size(); ) {
T x = e[i].x;
T dx = x - lastX;
if (dx) res += dx * st.query();
while (i < e.size() && e[i].x == x) {
// 注意:这里的y1,y2已经是内部开区间坐标了
int L = lower_bound(st.ys.begin(), st.ys.end(), e[i].y1) - st.ys.begin();
int R = lower_bound(st.ys.begin(), st.ys.end(), e[i].y2) - st.ys.begin() - 1;
if (L <= R) st.upd(1, 0, st.n-1, L, R, e[i].mark);
i++;
}
lastX = x;
}
return res;
}
};
// ==================== 使用 ====================
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
long long H, W, h, w;
int n;
cin >> H >> W >> h >> w >> n;
RectUnion<ll> ru;
for (int i = 0; i < n; i++) {
long long r, c;
cin >> r >> c;
long long x1 = max(1LL, r - h + 1);
long long y1 = max(1LL, c - w + 1);
long long x2 = min(H - h + 1, r);
long long y2 = min(W - w + 1, c);
// 直接传闭区间,模板内部处理转换
if (x1 <= x2 && y1 <= y2) ru.add(x1, y1, x2, y2);
//左下- 右上
}
long long total = (H - h + 1) * (W - w + 1);
long long bad = ru.solve();
cout << total - bad << '\n';
return 0;
}```