[BZOJ1176][[Balkan2007]Mokia][CDQ分治]
题目大意:
维护一个W*W的矩阵,初始值均为S.每次操作可以增加某格子的权值,或询问某子矩阵的总权值.修改操作数M<=160000,询问数Q<=10000,W<=2000000.
思路:
一道双倍经验题,另一题提交地址:http://www.lydsy.com/JudgeOnline/problem.php?id=2683
这应该是一道CDQ分治入门题了吧,CDQ介绍地址:http://blog.csdn.net/g1n0st/article/details/56839817
和BZOJ2716类似,为了将修改维护成询问的前缀,这道题也需要引入分治的思想。如下图所示,一个坐标为 (x1,y1,x2,y2) 内的矩形,可以拆分为 s1(0,0,x2,y1) , s2(0,0,x1,y2) , s3(0,0,x1,y1) , s4(0,0,x2,y2) 四个子矩形。利用容斥原理,求原矩形内的点集,就相当于求 s3+s4−s1−s2 。
考虑到四个子矩形的左下角坐标都是 (0,0) ,那么就是把一个询问的矩形拆成四个询问点,询问第一象限内每个询问点左下角的点集,然后容斥一下就好了。
代码:
完。
#include <bits/stdc++.h>
#define lowbit(x) ((x) & (-x))
using namespace std;
const int Maxn = 2000010, Maxm = 200010;
inline char get(void) {
static char buf[1000000], *p1 = buf, *p2 = buf;
if (p1 == p2) {
p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin);
if (p1 == p2) return EOF;
}
return *p1++;
}
inline void read(int &x) {
x = 0; static char c; bool minus = false;
for (; !(c >= '0' && c <= '9'); c = get()) if (c == '-') minus = true;
for (; c >= '0' && c <= '9'; x = x * 10 + c - '0', c = get()); if (minus) x = -x;
}
int t[Maxn], n, ans[Maxn];
inline void insert(int x, int v) {
for (; x <= n; x += lowbit(x)) t[x] += v;
}
inline int query(int x) {
static int sum; sum = 0;
for (; x; x -= lowbit(x)) sum += t[x];
return sum;
}
struct Abcd {
int x, y, op, id, bl, v;
Abcd(void) {}
Abcd(int x, int y, int v, int op, int id, int bl) :
x(x), y(y), v(v), op(op), id(id), bl(bl) {}
friend bool operator < (const Abcd &a, const Abcd &b) {
if (a.x == b.x && a.y == b.y) return a.id < b.id;
if (a.x == b.x) return a.y < b.y;
return a.x < b.x;
}
} oo[Maxm << 2], tmp[Maxm << 2];
int tot, bl;
inline void solve(int l, int r) {
if (l == r) return ;
int mid = (l + r) >> 1;
for (int i = l; i <= r; i++) {
if (oo[i].op == 1 && oo[i].id <= mid) insert(oo[i].y, oo[i].v);
if (oo[i].op == 2 && oo[i].id > mid) {
if (oo[i].v) ans[oo[i].bl] += query(oo[i].y);
else ans[oo[i].bl] -= query(oo[i].y);
}
}
for (int i = l; i <= r; i++) {
if (oo[i].op == 1 && oo[i].id <= mid) insert(oo[i].y, -oo[i].v);
}
int l1 = l, l2 = mid + 1;
for (int i = l; i <= r; i++) {
if (oo[i].id <= mid) tmp[l1++] = oo[i];
else tmp[l2++] = oo[i];
}
for (int i = l; i <= r; i++) {
oo[i] = tmp[i];
}
solve(l, mid), solve(mid + 1, r);
}
int main(void) {
//freopen("in.txt", "r", stdin);
read(n); read(n); int op, x, y, v, x1, y1;
while (1) {
read(op);
if (op == 3) break;
if (op == 1) {
read(x), read(y), read(v);
oo[++tot] = Abcd(x, y, v, 1, tot, 0);
} else {
read(x), read(y), read(x1), read(y1);
oo[++tot] = Abcd(x1, y1, 1, 2, tot, ++bl);
oo[++tot] = Abcd(x - 1, y - 1, 1, 2, tot, bl);
oo[++tot] = Abcd(x - 1, y1, 0, 2, tot, bl);
oo[++tot] = Abcd(x1, y - 1, 0, 2, tot, bl);
}
}
sort(oo + 1, oo + 1 + tot);
solve(1, tot);
for (int i = 1; i <= bl; i++) {
printf("%d\n", ans[i]);
}
return 0;
}
By g1n0st