给你一个序列,下标从 1 到 n。
然后有两类操作,要么是给出 k,l,r,x 把所有下标 %k 的值在 l~r 之间的位置都加上 x。
要么是区间求和。
头文件 D
题目大意
给你一个序列,下标从 1 到 n。
然后有两类操作,要么是给出 k,l,r,x 把所有下标 %k 的值在 l~r 之间的位置都加上 x。
要么是区间求和。
思路
发现没有什么比较好的数据结构能实现。
考虑观察它修改的性质。
如果它 k 很大,那修改的段就很小,可以直接暴力枚举每个段。
如果它 k 很小,那它修改段很多,但是每段很小,可以暴力用前缀和的方法统计。
所以我们考虑使用平衡规划。
自然分成 k⩽√n 和 k>√n 两个部分。
第一个部分,我们直接 fi,j 为 k=i 的修改,它第 j 个位置是加了 fi,j。
然后你在每次搞了就重新计算前缀和 gi,j。
然后就可以很快的统计了。
第二个部分,直接暴力找每一段线段树赋值,然后插叙就直接查询线段树即可。
代码
#include<cmath>
#include<cstdio>
#include<iostream>
#define ll long long
using namespace std;
ll n, m, op, x, y, k, z;
ll f[501][501], g[501][501];
ll a[200001], ans, sum[501];
struct XD_tree {
ll v[200002 << 2], lzy[200002 << 2];
void up(ll now) {
v[now] = v[now << 1] + v[now << 1 | 1];
}
void down(ll now, ll l, ll r) {
if (!lzy[now]) return ;
ll mid = (l + r) >> 1;
v[now << 1] += lzy[now] * (mid - l + 1); v[now << 1 | 1] += lzy[now] * (r - mid);
lzy[now << 1] += lzy[now]; lzy[now << 1 | 1] += lzy[now];
lzy[now] = 0;
}
void build(ll now, ll l, ll r) {
if (l == r) {
v[now] = a[l]; return ;
}
ll mid = (l + r) >> 1;
build(now << 1, l, mid);
build(now << 1 | 1, mid + 1, r);
up(now);
}
void insert(ll now, ll l, ll r, ll L, ll R, ll va) {
if (L <= l && r <= R) {
lzy[now] += va; v[now] += 1ll * va * (r - l + 1);
return ;
}
down(now, l, r);
ll mid = (l + r) >> 1;
if (L <= mid) insert(now << 1, l, mid, L, R, va);
if (mid < R) insert(now << 1 | 1, mid + 1, r, L, R, va);
up(now);
}
ll query(ll now, ll l, ll r, ll L, ll R) {
if (L <= l && r <= R) return v[now];
down(now, l, r);
ll mid = (l + r) >> 1, re = 0;
if (L <= mid) re += query(now << 1, l, mid, L, R);
if (mid < R) re += query(now << 1 | 1, mid + 1, r, L, R);
return re;
}
}T;
int main() {
scanf("%lld %lld", &n, &m);
for (ll i = 1; i <= n; i++) scanf("%lld", &a[i]);
T.build(1, 1, n);
ll lim = sqrt(n);
while (m--) {
scanf("%lld", &op);
if (op == 1) {
scanf("%lld %lld %lld %lld", &k, &x, &y, &z);
if (k <= lim) {
for (ll i = x; i <= y; i++) {
f[k][i] += z;
}
g[k][0] = f[k][0];
for (int i = 1; i < k; i++)
g[k][i] = g[k][i - 1] + f[k][i];
sum[k] += (y - x + 1) * z;
}
else {
for (ll i = 0; i + x <= n; i += k)
T.insert(1, 1, n, i + x, min(n, i + y), z);
}
}
if (op == 2) {
scanf("%lld %lld", &x, &y);
ans = T.query(1, 1, n, x, y);
for (ll i = 1; i <= lim; i++) {
ll nm1 = x / i, nm2 = y / i;
ans += sum[i] * (nm2 - nm1);
ans += g[i][y % i];
if (x % i != 0) ans -= g[i][x % i - 1];
}
printf("%lld\n", ans);
}
}
return 0;
}
__EOF__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现