洛谷P3948 数据结构
标签
- 前缀和
- 差分
简明题意
- 需要你支持两种操作
- 将区间[L,R]每个数都加上x
- 询问[L,R]内的a[i],满足min <= a[i] * i % mod <= max,其中min,max,mod都是题目给定的
思路
- 首先这题不是数据结构题…这题我们考虑一步步优化
- 写一个纯暴力,可以拿70分。
- 考虑到最后有很多查询,但是没有修改,我们前缀和出pre[i],表示到i为止满足 m i n < = a [ i ] ∗ i min <= a[i] * i % mod <= max min<=a[i]∗i的个数,然后这里的O(n)查询就变成了O(1)…然后,我们惊奇的发现,AC了…
- 但是我们不能就这样满足了,因为上面的操作1和操作2仍然是O(n)的。我们去考虑优化上面的操作
- 我们可以在修改时用差分O(1)修改,然后在查询时通过差分还原出原数组,然后暴力O(n)…
- 这样优化后大概是5000ms,不进行这一步优化,大概是8000ms
- 结束…
注意事项
- 用了差分再用前缀和,记得要还原两次
总结
- 多考虑差分,前缀和,这样能将两个O(n)的操作中的其中一个降低到O(1)
- 涉及到区间加和可以差分,统计数目可以前缀和
AC代码
#include<cstdio>
const int maxn = 8e4 + 10;
int n, m, mod, min, max;
long long a[maxn];
void solve()
{
long long cf[maxn] = { 0 };
scanf("%d%d%d%d%d", &n, &m, &mod, &min, &max);
while (m--)
{
char opt[10];
scanf("%s", opt);
if (opt[0] == 'A')
{
int l, r, x;
scanf("%d%d%d", &l, &r, &x);
cf[l] += x, cf[r + 1] -= x;
}
else if (opt[0] == 'Q')
{
int l, r;
scanf("%d%d", &l, &r);
long long cnt = 0, las = 0;
for (int i = 1; i <= n; i++)
{
long long x = las + cf[i];
las = x;
if (i >= l && i <= r && x * i % mod <= max && x * i % mod >= min)
cnt++;
}
printf("%lld\n", cnt);
}
}
for (int i = 1; i <= n; i++)
a[i] = a[i - 1] + cf[i];
int pre[maxn] = { 0 };
for (int i = 1; i <= n; i++)
pre[i] = pre[i - 1] + (i * a[i] % mod >= min && i * a[i] % mod <= max);
scanf("%d", &m);
while (m--)
{
int l, r;
scanf("%d%d", &l, &r);
printf("%d\n", pre[r] - pre[l - 1]);
}
}
int main()
{
freopen("Testin.txt", "r", stdin);
solve();
return 0;
}
双倍经验
- 无