题目链接:BZOJ1176
题目大意
要求支持两种操作:
Add i j x
,点
(i,j)
权值+
x
。
点坐标
≤2e6
,add操纵
≤16e4
,query操作
≤1e4
。
分析
1. 显然不能用二维树状数组做了,考虑CDQ分治。
2. CDQ之后,每次分治就变成了一个简化版的问题:已知若干个add操作,询问若干个query操作,所有query操作在add操作之后。
3. 把每个query拆成两个操作:
q1 x1−1 y1 y2
和
q2 x2 y1 y2
,将所有操作按x坐标排序,然后类似前缀和用
ansq2−ansq1
就可以求出答案了。
上代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int N = 1e4 + 10;
const int M = 2e5 + 10;
const int L = 2e6 + 10;
int n, m;
inline int read() {
char ch;
int ans = 0, neg = 1;
while (!isdigit(ch = getchar()))
if (ch == '-') neg = -1;
while (isdigit(ch))
ans = ans * 10 + ch - '0', ch = getchar();
return ans * neg;
}
struct Op {
int type, x, y, val, *plc;
Op() {}
Op(int _x, int _y, int *_plc) : x(_x), y(_y), plc(_plc) { type = 0; }
inline bool operator < (const Op &a) const {
return x < a.x;
}
} op[M];
int cntAns;
struct Ans {
int plus, minus;
inline void output() {
printf("%d\n", plus - minus);
}
} ans[N];
void init() {
read(), m = read();
while (op[n + 1].type = read(), op[n + 1].type != 3) {
if (op[++n].type == 1)
op[n].x = read(), op[n].y = read(), op[n].val = read();
else {
int x1 = read(), y1 = read(), x2 = read(), y2 = read();
op[n] = Op(x1 - 1, y1 - 1, &ans[++cntAns].plus);
op[++n] = Op(x1 - 1, y2, &ans[cntAns].minus);
op[++n] = Op(x2, y1 - 1, &ans[cntAns].minus);
op[++n] = Op(x2, y2, &ans[cntAns].plus);
}
}
}
#define lowbit(a) (a & (-a))
int sum[L];
void modify(int a, int c) {
for (int i = a; i <= m; i += lowbit(i)) sum[i] += c;
}
int query(int a) {
int ans = 0;
for (int i = a; i; i -= lowbit(i)) ans += sum[i];
return ans;
}
Op ary[M];
int getAry(int l, int r) {
int mid = (l + r) >> 1;
int ll = l, rr = mid + 1, tmp = l;
for (; rr <= r && op[rr].type; ++rr);
for (; ll <= mid && !op[ll].type; ++ll);
while (ll <= mid && rr <= r) {
if (op[ll].x <= op[rr].x)
ary[tmp++] = op[ll++];
else ary[tmp++] = op[rr++];
for (; rr <= r && op[rr].type; ++rr);
for (; ll <= mid && !op[ll].type; ++ll);
}
while (rr <= r) {
ary[tmp++] = op[rr++];
for (; rr <= r && op[rr].type; ++rr);
}
while (ll <= mid) {
ary[tmp++] = op[ll++];
for (; ll <= mid && !op[ll].type; ++ll);
}
return tmp - 1;
}
void mergeSort(int l, int r) {
int mid = (l + r) >> 1;
int ll = l, rr = mid + 1, tmp = l;
while (ll <= mid && rr <= r) {
if (op[ll].x <= op[rr].x)
ary[tmp++] = op[ll++];
else ary[tmp++] = op[rr++];
}
while (rr <= r) ary[tmp++] = op[rr++];
while (ll <= mid) ary[tmp++] = op[ll++];
for (int i = l; i <= r; ++i) op[i] = ary[i];
}
void figure(int l, int r) {
if (l == r) return;
int mid = (l + r) >> 1;
figure(l, mid), figure(mid + 1, r);
int rr = getAry(l, r);
for (int i = l; i <= rr; ++i)
if (ary[i].type) modify(ary[i].y, ary[i].val);
else *ary[i].plc += query(ary[i].y);
for (int i = l; i <= rr; ++i)
if (ary[i].type) modify(ary[i].y, -ary[i].val);
mergeSort(l, r);
}
int main() {
init();
figure(1, n);
for (int i = 1; i <= cntAns; ++i)
ans[i].output();
return 0;
}
以上