每日一题30.储物点的距离 (区间处理,前缀和/线段树//树状数组)

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了每日一题30.储物点的距离 (区间处理,前缀和/线段树//树状数组)相关的知识,希望对你有一定的参考价值。

补题链接:Here

算法涉及:前缀和,思维

一个数轴,每一个储物点会有一些东西,同时它们之间存在距离。

每次给个区间 \\([l,r]\\) ,查询把这个区间内所有储物点的东西运到另外一个储物点的代价是多少?

比如储物 \\(i\\) 点有\\(x\\) 个东西,要运到储物点 \\(j\\) ,代价为 \\(x*dit(i,j)\\)

dist(i, j) = abs(i - j) 就是储物点间的距离。

【解题思路】

对于一个区间 \\([l, r]\\) , 总的代价为 \\(\\sum\\limits_{i = l}^{r}b[i] * abs(a[i] - a[x])\\)
对于最终点 \\(x\\) , 我们可以分三种情况:

  • \\(r\\le x\\),那么上面式子里的绝对值去掉得到 \\(\\sum\\limits_{i = l}^{r}b[i] * abs(a[i] - a[x]) = a[x]\\sum\\limits_{i = l}^{r}b[i] - \\sum\\limits_{i = l}^{r}a[i]b[i]\\)

  • \\(x\\le l\\),那么上面式子里的绝对值去掉得到\\(\\sum\\limits_{i = l}^{r}b[i] * abs(a[i] - a[x]) = -a[x]\\sum\\limits_{i = l}^{r}b[i] + \\sum\\limits_{i = l}^{r}a[i]b[i]\\)

  • \\(l < x < r\\) , 那么对区间 \\([l,x-1],[x,r]\\) 分别做上述的操作即可

观察发现可以维护两个前缀和, \\(\\sum\\limits_{i = l}^{r}a[i]b[i]\\)\\(\\sum\\limits_{i = l}^{r}b[i]\\) , 那么上述每次查询操作就能够 \\(\\mathcal{O}(1)\\)

  • 最后万分提醒,取模、取模再取模。。。Debug 超久
using ll = long long;
const int mod = 1e9 + 7;
const int N = 2e5 + 10;
ll a[N], b[N], c[N], sum[N];
void solve() {
    int n, m;
    cin >> n >> m;
    for (int i = 2; i <= n; ++i) {
        cin >> a[i]; // n - 1个数,第i个数表示第i个储物点与第i+1个储物点的距离ai
        a[i] = (a[i - 1] + a[i]) %  mod;
    }
    for (int i = 1; i <= n; ++i) {
        cin >> b[i]; // 每个储物点的东西个数bi
        c[i] = (a[i] * b[i]) % mod;
        b[i] = (b[i] + b[i - 1]) % mod;
        sum[i] = (sum[i - 1] + c[i]) % mod;
    }
    int l, r, x;
    while (m--) {
        cin >> x >> l >> r;
        ll ans = 0;
        if (x >= r) { // 情况 1
            ans = a[x] * ((b[r] - b[l - 1] + mod) % mod) % mod;
            ans = (ans - ((sum[r] - sum[l - 1] + mod) % mod) + mod) % mod;
            ans = (ans + mod) % mod;
            cout << ans << "\\n";
        } else if (l >= x) { // 情况 2
            ans = (sum[r] - sum[l - 1] + mod) % mod;
            ans = (ans - a[x] * ((b[r] - b[l - 1] + mod) % mod) + mod)  % mod;
            ans = (ans + mod) % mod;
            cout << ans << "\\n";
        } else { // 情况 3
            ll ans1 = (sum[r] - sum[x - 1] + mod) % mod;
            ans1 = (ans1 - (a[x] * ((b[r] - b[x - 1]) + mod % mod)) + mod) % mod;
            ans1 = (ans1 + mod) % mod;
            ll ans2 = (a[x] * ((b[x - 1] - b[l - 1] + mod) % mod)) % mod;
            ans2 = (ans2 - ((sum[x - 1] - sum[l - 1] + mod) % mod) + mod) % mod;
            ans2 = (ans2 + mod) % mod;
            cout << (ans1 + ans2) % mod << "\\n";
        }
    }
}

以上是关于每日一题30.储物点的距离 (区间处理,前缀和/线段树//树状数组)的主要内容,如果未能解决你的问题,请参考以下文章

B.储物点的距离

P3932 浮游大陆的68号岛

luogu P3932 浮游大陆的68号岛

洛谷 P3932 浮游大陆的68号岛 题解

洛谷10月月赛R2·浴谷八连测R3 -Chtholly-T1

寒假每日一题(提高组)Week 2 完结