知识点: CDQ分治
原题面 Luogu darkbzoj
扯
套路题,20 min A 了。
什么嘛,我写的还是挺快的嘛(
题意简述
给定一初始全为 \(0\) 的 \(w\times w\) 的格子图。
有若干次操作,每次操作是下列形式之一:
- 增加某格子的权值,共有 \(m\) 次。
- 询问某子矩阵的权值和,共有 \(q\) 次。
\(1\le w\le 2\times 10^6\),\(1\le m\le 1.6\times 10^5\),\(1\le q\le 10^4\)。
分析题意
套路题,考虑二维前缀和的形式,容斥一下将询问矩阵拆成四个子询问矩阵。
问题变为对于每一个询问 \((x_i,y_i)\) 统计时间先于它的,在其左下方的点的数量。
显然的三维偏序形式,Cdq 直接搞即可。
一些细节
拆分询问后,把答案存在四个询问中时间最小的上。
cdq 打乱了原有时间顺序,为方便输出,代码中记录了时间戳。
代码实现
//知识点:CDQ 分治
/*
By:Luckyblock
*/
#include <algorithm>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#define ll long long
const int kMaxn = 2e6 + 10;
//=============================================================
struct Data {
int type, t, x, y, a;
} a[kMaxn], tmp[kMaxn];
int w, n, ans[kMaxn];
bool vis[kMaxn];
//=============================================================
inline int read() {
int f = 1, w = 0;
char ch = getchar();
for (; !isdigit(ch); ch = getchar())
if (ch == '-') f = -1;
for (; isdigit(ch); ch = getchar()) w = (w << 3) + (w << 1) + (ch ^ '0');
return f * w;
}
void GetMax(int &fir_, int sec_) {
if (sec_ > fir_) fir_ = sec_;
}
void GetMin(int &fir_, int sec_) {
if (sec_ < fir_) fir_ = sec_;
}
namespace TreeArray {
#define lowbit(x) (x&-x)
const int kMaxm = 2e6 + 10;
int time, ti[kMaxn], t[kMaxn];
void Clear() {
time ++;
}
void Add(int pos_, int val_) {
for (; pos_ <= w; pos_ += lowbit(pos_)) {
if (ti[pos_] < time) {
t[pos_] = 0;
ti[pos_] = time;
}
t[pos_] += val_;
}
}
int Sum(int pos_) {
int ret = 0;
for (; pos_; pos_ -= lowbit(pos_)) {
if (ti[pos_] < time) {
t[pos_] = 0;
ti[pos_] = time;
}
ret += t[pos_];
}
return ret;
}
}
#define mid ((l_+r_)>>1)
void Cdq(int l_, int r_) {
if (l_ == r_) return ;
Cdq(l_, mid), Cdq(mid + 1, r_);
int p1 = l_, p2 = mid + 1, p = l_ - 1;
for (; p2 <= r_; ++ p2) {
for (; p1<= mid && a[p1].x <= a[p2].x; ++ p1) {
tmp[++ p] = a[p1];
if (! a[p1].type) TreeArray :: Add(a[p1].y, a[p1].a);
}
tmp[++ p] = a[p2];
if (! a[p2].type) continue ;
ans[a[p2].t] += a[p2].type * TreeArray :: Sum(a[p2].y);
}
for (; p1 <= mid; ++ p1) tmp[++ p] = a[p1];
for (int i = l_; i <= r_; ++ i) a[i] = tmp[i];
TreeArray :: Clear();
}
//=============================================================
int main() {
while (true) {
int opt = read();
if (opt == 3) break;
if (opt == 0) w = read();
if (opt == 1) {
a[++ n] = (Data) {0, n, read(), read(), read()};
}
if (opt == 2) {
int x1 = read(), y1 = read(), x2 = read(), y2 = read();
vis[n + 1] = true;
a[++ n] = (Data) {1, n, x2, y2, 0};
a[++ n] = (Data) {- 1, n - 1, x1 - 1, y2, 0};
a[++ n] = (Data) {- 1, n - 2, x2, y1 - 1, 0};
a[++ n] = (Data) {1, n - 3, x1 - 1, y1 - 1, 0};
}
}
Cdq(1, n);
for (int i = 1; i <= n; ++ i) {
if (vis[i]) printf("%d\n", ans[i]);
}
return 0;
}