【数据结构】分块
单点修改,区间求和
已验证:
https://www.luogu.com.cn/problem/P3374 (单点修改,区间求和)
rt[i]: i位置所属的块的序号
va[i]: i位置的值
lb[b]: 序号b的块的左边界的位置
rb[b]: 序号b的块的左边界的位置
sm[b]: 序号b的块的区间求和
struct Block {
static const int MAXN = 500000 + 5;
static const int MAXB = 500000 + 5;
int rt[MAXN];
ll va[MAXN];
int lb[MAXB];
int rb[MAXB];
ll sm[MAXB];
void Add(int x, ll v) {
va[x] += v;
sm[rt[x]] += v;
}
ll Sum(int l, int r) {
if(rt[l] == rt[r]) {
ll res = 0LL;
for(int i = l; i <= r; ++i)
res += va[i];
return res;
} else {
ll res = 0LL;
for(int i = l; i <= rb[rt[l]]; ++i)
res += va[i];
for(int i = lb[rt[r]]; i <= r; ++i)
res += va[i];
for(int b = rt[l] + 1; b <= rt[r] - 1; ++b)
res += sm[b];
return res;
}
}
void Init(int n) {
int blk = (int)sqrt(n) + 1;
int cntblk = (n + blk - 1) / blk;
memset(va, 0LL, sizeof(va[0]) * (n + 1));
memset(lb, INF, sizeof(lb[0]) * (cntblk + 1));
memset(rb, -INF, sizeof(rb[0]) * (cntblk + 1));
memset(sm, 0LL, sizeof(sm[0]) * (cntblk + 1));
for(int i = 1; i <= n; ++i) {
rt[i] = (i + blk - 1) / blk;
lb[rt[i]] = min(lb[rt[i]], i);
rb[rt[i]] = max(rb[rt[i]], i);
}
}
} blk;
区间修改,单点求值
已验证:
https://www.luogu.com.cn/problem/P3368 (区间修改,单点求值)
rt[i]: i位置所属的块的序号
va[i]: i位置的值
lb[b]: 序号b的块的左边界的位置
rb[b]: 序号b的块的左边界的位置
lz[b]: 序号b的块的懒惰标记
struct Block {
static const int MAXN = 500000 + 5;
static const int MAXB = 500000 + 5;
int rt[MAXN];
int va[MAXN];
int lb[MAXB];
int rb[MAXB];
int lz[MAXB];
void Add(int l, int r, int v) {
if(rt[l] == rt[r]) {
for(int i = l; i <= r; ++i)
va[i] += v;
} else {
for(int i = l; i <= rb[rt[l]]; ++i)
va[i] += v;
for(int i = lb[rt[r]]; i <= r; ++i)
va[i] += v;
for(int b = rt[l] + 1; b <= rt[r] - 1; ++b)
lz[b] += v;
}
}
int Val(int x) {
return va[x] + lz[rt[x]];
}
void Init(int n) {
int blk = (int)sqrt(n) + 1;
int cntblk = (n + blk - 1) / blk;
memset(va, 0, sizeof(va[0]) * (n + 1));
memset(lb, INF, sizeof(lb[0]) * (cntblk + 1));
memset(rb, -INF, sizeof(rb[0]) * (cntblk + 1));
memset(lz, 0, sizeof(lz[0]) * (cntblk + 1));
for(int i = 1; i <= n; ++i) {
rt[i] = (i + blk - 1) / blk;
lb[rt[i]] = min(lb[rt[i]], i);
rb[rt[i]] = max(rb[rt[i]], i);
}
}
} blk;
区间修改,区间求和
区间修改多出一个懒惰标记。
已验证:
https://www.luogu.com.cn/problem/P3374 (单点修改,区间求和)
https://www.luogu.com.cn/problem/P3368 (区间修改,单点求值)
https://www.luogu.com.cn/problem/P3372 (区间修改,区间求和)
rt[i]: i位置所属的块的序号
va[i]: i位置的值
lb[b]: 序号b的块的左边界的位置
rb[b]: 序号b的块的左边界的位置
sm[b]: 序号b的块的区间求和
lz[b]: 序号b的块的懒惰标记
struct Block {
static const int MAXN = 500000 + 5;
static const int MAXB = 500000 + 5;
int rt[MAXN];
ll va[MAXN];
int lb[MAXB];
int rb[MAXB];
ll sm[MAXB];
ll lz[MAXB];
void Add(int l, int r, ll v) {
if(rt[l] == rt[r]) {
for(int i = l; i <= r; ++i)
va[i] += v;
sm[rt[l]] += v * (r - l + 1);
} else {
for(int i = l; i <= rb[rt[l]]; ++i)
va[i] += v;
sm[rt[l]] += v * (rb[rt[l]] - l + 1);
for(int i = lb[rt[r]]; i <= r; ++i)
va[i] += v;
sm[rt[r]] += v * (r - lb[rt[r]] + 1);
for(int b = rt[l] + 1; b <= rt[r] - 1; ++b) {
sm[b] += v * (rb[b] - lb[b] + 1);
lz[b] += v;
}
}
}
ll Sum(int l, int r) {
if(rt[l] == rt[r]) {
ll res = 0LL;
for(int i = l; i <= r; ++i) {
res += va[i];
res += lz[rt[i]];
}
return res;
} else {
ll res = 0LL;
for(int i = l; i <= rb[rt[l]]; ++i)
res += va[i];
res += lz[rt[l]] * (rb[rt[l]] - l + 1);
for(int i = lb[rt[r]]; i <= r; ++i)
res += va[i];
res += lz[rt[r]] * (r - lb[rt[r]] + 1);
for(int b = rt[l] + 1; b <= rt[r] - 1; ++b)
res += sm[b];
return res;
}
}
void Init(int n) {
int blk = (int)sqrt(n) + 1;
int cntblk = (n + blk - 1) / blk;
memset(va, 0LL, sizeof(va[0]) * (n + 1));
memset(lb, INF, sizeof(lb[0]) * (cntblk + 1));
memset(rb, -INF, sizeof(rb[0]) * (cntblk + 1));
memset(sm, 0LL, sizeof(sm[0]) * (cntblk + 1));
memset(lz, 0LL, sizeof(lz[0]) * (cntblk + 1));
for(int i = 1; i <= n; ++i) {
rt[i] = (i + blk - 1) / blk;
lb[rt[i]] = min(lb[rt[i]], i);
rb[rt[i]] = max(rb[rt[i]], i);
}
}
} blk;