首页 > 其他分享 >E. Space Harbour

E. Space Harbour

时间:2024-02-13 13:00:14浏览次数:19  
标签:le Space cdot harbour int Harbour query type

E. Space Harbour

There are $n$ points numbered $1$ to $n$ on a straight line. Initially, there are $m$ harbours. The $i$-th harbour is at point $X_i$ and has a value $V_i$. It is guaranteed that there are harbours at the points $1$ and $n$. There is exactly one ship on each of the $n$ points. The cost of moving a ship from its current location to the next harbour is the product of the value of the nearest harbour to its left and the distance from the nearest harbour to its right. Specifically, if a ship is already at a harbour, the cost of moving it to the next harbour is $0$.

Additionally, there are $q$ queries, each of which is either of the following $2$ types:

  • $1$ $x$ $v$ — Add a harbour at point $x$ with value $v$. It is guaranteed that before adding the harbour, there is no harbour at point $x$.
  • $2$ $l$ $r$ — Print the sum of the cost of moving all ships at points from $l$ to $r$ to their next harbours. Note that you just need to calculate the cost of moving the ships but not actually move them.

Input

The first line contains three integers $n$, $m$, and $q$ ($2 \le m \le n \le 3 \cdot 10^5$, $1 \le q \le 3 \cdot 10^5$) — the number of points, harbours, and queries, respectively.

The second line contains $m$ distinct integers $X_1, X_2, \ldots, X_m(1 \le X_i \le n)$ — the position at which the $i$-th harbour is located.

The third line contains $m$ integers $V_1, V_2, \ldots, V_m(1 \le V_i \le 10^7)$ — the value of the $i$-th harbour.

Each of the next $q$ lines contains three integers. The first integer is $t$ ($1\le t \le 2$) — type of query. If $t=1$, then the next two integers are $x$ and $v$ ($2 \le x \le n - 1$, $1 \le v \le 10^7$) — first-type query. If $t=2$, then the next two integers are $l$ and $r$ ($1 \le l \le r \le n$) — second-type query.

It is guaranteed that there is at least one second-type query.

Output

For every second-type query, print one integer in a new line — answer to this query.

Example

input

8 3 4
1 3 8
3 24 10
2 2 5
1 5 15
2 5 5
2 7 8

output

171
0
15

Note

For the first type $2$ query, the cost for ships at positions $2$, $3$, $4$ and $5$ are $3(3 \times 1)$, $0$, $96(24 \times 4)$ and $72(24 \times 3)$ respectively.

For the second type $2$ query, since the ship at position $5$ is already at a harbour, so the cost is $0$.

For the third type $2$ query, the cost for ships at position $7$ and $8$ are $15(15 \times 1)$ and $0$ respectively.

 

解题思路

  初始时第 $i$ 个位置的代价为 $w_i = v_{l_i} \cdot (r_i - i)$,其中 $l_i$ 指左边最靠近 $i$ 的被标记的位置,$r_i$ 指右边最靠近 $i$ 的被标记的位置(用 std::set 维护已标记的位置)。当标记位置 $x$ 时,只有 $i \in [l_x + 1, r_x - 1]$ 的 $w_i$ 会受到影响。把这个范围分成两个部分来处理。

  对于 $i \in [l_x + 1, x]$ 的位置,在标记了 $x$ 后,每一个 $i$ 右边被标记的位置变成了 $x$,即每一个 $w_i$ 都从原本的 $v_{l_i} \cdot (r_i - i)$ 变成 $v_{l_i} \cdot (x - i)$。因此需要对这个区间内的 $w_i$ 都加上定值 $-v_{l_i} \cdot (r_i - x)$。

  对于 $i \in [x + 1, r_i - 1]$ 的位置,在标记了 $x$ 后,每一个 $i$ 左边被标记的位置变成了 $x$,即每一个 $w_i$ 都从原本的 $v_{l_i} \cdot (r_i - i)$ 变成 $v_{x} \cdot (r_i - i)$。因此需要对这个区间内的 $w_i$ 分别加上 $(v_x - v_{l_i}) \cdot (r_i - i)$,这个值会随着 $i$ 而变化。这相当于将一个首项为 $(v_x - v_{l_i}) \cdot (r_i - x - 1)$,公差为 $v_{l_i} - v_x$ 的等差数列加到区间 $[x + 1, r_i - 1]$ 的每个 $w_i$ 上。

  为了统一处理,这里把对区间 $[l_x + 1, x]$ 的处理也看作是给区间加上首项为 $-v_{l_i} \cdot (r_i - x)$,公差为 $0$ 的等差数列。

  区间加等差数列可以参考这两题:无聊的数列牛牛的等差数列。需要用线段树来维护 $w_i$ 的差分数组,以及差分的二阶前缀和。

  当给区间 $[l,r]$ 加上首项为 $k$,公差为 $d$ 的等差数列时,考虑对差分数组的影响。根据定义差分数组的 $g_i = w_i - w_{i-1}$,操作相当于给 $g_l$ 加上 $k$,$g_{l+1} \sim g_{r}$ 都加上 $d$,$g_{r+1}$ 加上 $-(k + (r-l) \cdot d)$。因此如果用线段树来维护差分数组,那么就可以很好的支持单点和区间修改,前缀 $[1,i]$ 的和就是 $w_i$。

  但题目的询问是某个区间的 $w_i$,因此还需要维护关于 $g_i$ 的前缀和的前缀和,即二阶前缀和。如果要求 $w_i$ 的前缀 $[1,k]$ 的和:

\begin{align*}
\sum_{i=1}^{k}{w_i} =& \sum_{i=1}^{k}\sum_{j=1}^{i}{g_j} \\
=& g_1 + (g_1 + g_2) + (g_1 + g_2 + g_3) + \ldots + (g_1 + g_2 + \ldots + g_k) \\
=& k \cdot g_1 + (k-1) \cdot g_2 + \ldots + g_k \\
=& k \cdot (g_1 + g_2 + \cdots + g_k) + \left[ 0 \cdot g_1 + 1 \cdot g_2 + \ldots + (k-1) \cdot g_k \right] \\
=& k \cdot \sum_{i=1}^{k}{g_i} + \sum_{i=1}^{k}{(i-1)g_i}
\end{align*}

  因此线段树除了需要维护差分数组 $g_i$ 的区间和 $s1$,还要维护 $(i-1)g_i$ 的区间和 $s2$。当需要给线段节点所维护区间 $[l,r]$ 的 $g_i$ 都加上 $c$,那么就有 $s_1 \gets s_1 + c \cdot (r-l+1)$,$s_2 \gets s2 + c \cdot \frac{(r-l+1) \cdot (l+r)}{2}$。

  AC 代码如下,时间复杂度为 $O(q \log{n})$:

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 3e5 + 10;

int a[N], b[N];
LL w[N];
set<int> st;
struct Node {
    int l, r;
    LL s1, s2, add;
}tr[N * 4];

void pushup(int u) {
    tr[u].s1 = tr[u << 1].s1 + tr[u << 1 | 1].s1;
    tr[u].s2 = tr[u << 1].s2 + tr[u << 1 | 1].s2;
}

void build(int u, int l, int r) {
    tr[u] = {l, r, 0, 0, 0};
    if (l == r) {
        tr[u].s1 = w[l] - w[l - 1];
        tr[u].s2 = tr[u].s1 * (l - 1);
    }
    else {
        int mid = l + r >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
        pushup(u);
    }
}

void upd(int u, LL c) {
    int len = tr[u].r - tr[u].l + 1;
    tr[u].s1 += c * len;
    tr[u].s2 += c * len * (tr[u].l + tr[u].r - 2) / 2;
    tr[u].add += c;
}

void pushdown(int u) {
    if (tr[u].add) {
        upd(u << 1, tr[u].add);
        upd(u << 1 | 1, tr[u].add);
        tr[u].add = 0;
    }
}

void modify(int u, int l, int r, LL c) {
    if (tr[u].l >= l && tr[u].r <= r) {
        upd(u, c);
    }
    else {
        pushdown(u);
        int mid = tr[u].l + tr[u].r >> 1;
        if (l <= mid) modify(u << 1, l, r, c);
        if (r >= mid + 1) modify(u << 1 | 1, l, r, c);
        pushup(u);
    }
}

LL query(int u, int l, int r) {
    if (l > r) return 0;
    if (tr[u].l >= l && tr[u].r <= r) return r * tr[u].s1 - tr[u].s2;
    pushdown(u);
    int mid = tr[u].l + tr[u].r >> 1;
    LL ret = 0;
    if (l <= mid) ret = query(u << 1, l, r);
    if (r >= mid + 1) ret += query(u << 1 | 1, l, r);
    return ret;
}

void add(int l, int r, LL k, LL d) {
    if (l > r) return;
    modify(1, l, l, k);
    modify(1, l + 1, r, d);
    modify(1, r + 1, r + 1, -(k + (r - l) * d));
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m, k;
    cin >> n >> m >> k;
    for (int i = 1; i <= m; i++) {
        cin >> a[i];
        st.insert(a[i]);
    }
    for (int i = 1; i <= m; i++) {
        cin >> b[a[i]];
    }
    for (int i = 1; i <= n; i++) {
        int l = *prev(st.upper_bound(i)), r = *st.lower_bound(i);
        w[i] = 1ll * b[l] * (r - i);
    }
    build(1, 1, n);
    while (k--) {
        int op, x, y;
        cin >> op >> x >> y;
        if (op == 1) {
            int l = *prev(st.upper_bound(x)), r = *st.lower_bound(x);
            add(l + 1, x, -1ll * b[l] * (r - x), 0);
            add(x + 1, r - 1, (y - b[l]) * (r - x - 1ll), b[l] - y);
            st.insert(x);
            b[x] = y;
        }
        else {
            cout << query(1, 1, y) - query(1, 1, x - 1) << '\n';
        }
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 921 (Div. 1, Div. 2) Editorial:https://codeforces.com/blog/entry/125137

  Educational Codeforces Round 126 (Rated for Div. 2)-D. Progressions Covering(区间加等差数列/思维):https://blog.csdn.net/m0_51979134/article/details/124129258

  牛客挑战赛39 牛牛的等差数列 (线段树 / 树状数组) (等差数列 高阶差分 高阶前缀和):https://blog.csdn.net/weixin_45799835/article/details/120820519

标签:le,Space,cdot,harbour,int,Harbour,query,type
From: https://www.cnblogs.com/onlyblues/p/18014513

相关文章

  • Linux Namespace
    LinuxNamespace是Linux内核提供的一种机制,用于实现进程之间的隔离。通过使用Namespace,可以将一组进程和资源限制在一个隔离的环境中,使它们看起来像在独立的系统上运行一样。PIDNamespace(进程隔离):PIDNamespace为进程提供了独立的进程ID空间,使得每个Namespace内的进程......
  • kubernetes---namespace(命名空间)
    1.查看namespace[root@k8s-master1~]#kubectlgetnamespaces#namespaces可以简写namespace或nsNAMESTATUSAGEdefaultActive130m #所有未指定Namespace的对象都会被默认分配在default命名空间kube-node-leaseActive130m kube-publ......
  • Docker:Failed to copy files, no space left on device
    主页个人微信公众号:密码应用技术实战个人博客园首页:https://www.cnblogs.com/informatics/问题描述在Mac上进行docker构建时,偶尔会遇到以下问题Failedtocopyfiles:userspacecopyfailed:write/var/lib/docker/volumes/xxx/_data/xxx.dbf:nospaceleftondevice......
  • 【K8S】namespace 一直处在terminating状态
    1、想要去删除k8s中的一个指定命名空间,刚开始使用命令kubectldeletens命名空间的名字#或者使用kubectldeletens命名空间的名字--force--grace-period=0使用以上两种命令均无法成功删除命名空间,只会使命名空间的状态为Terminating状态2、使用以下方法成功删除1)使......
  • 在K8s中,容器内如何获取pod和namespace名?
    在Kubernetes(K8s)中,容器可以通过DownwardAPI来获取Pod和Namespace的信息。以下是两种方法来实现这一点:通过环境变量获取获取Pod名称:在Pod的配置中,可以设置一个环境变量,将Pod的名字注入到容器内:apiVersion:v1kind:Podmetadata:name:my-podspec:containers:......
  • CF1924B Space Harbour
    思路可以观察到一件事情:在两个港口之间的船他们对应的价值都是一样的,都为左边港口的权值。因此对于这段区间的价值和就可以写成\(val\times\sumdis\)的形式,\(\sumdis\)便为这些船到右边港口的距离和。那么我们就可以按照港口把序列分成很多个区间来考虑。港口用一个set......
  • Powershell 并发任务 | Runspace 线程 | 结果获取
    介绍在PowerShell中进行多任务处理(Multithreading或ParallelProcessing)主要目的是提高脚本的执行效率和性能。对于需要处理大量数据或执行多个独立任务的脚本来说尤其有用。提高性能:多任务处理允许脚本同时执行多个任务,从而加快整体执行速度。对于需要处理大型数据集或执......
  • CodeForces 1924B Space Harbour
    洛谷传送门CF传送门不知道为什么好像大家在这题上花了挺久的。发现对于一对相邻的港口\((x_i,x_{i+1})\),\(x\in(x_i,x_{i+1})\)的花费是\(y_i(x_{i+1}-x)\)。拆开得\(y_ix_{i+1}-y_ix\)。考虑用set维护所有港口,这样可以知道一个港口左边和右边的港......
  • VBA001 String、Space関数
    VBAで全角スペースを指定数追加する(String)VBAで半角スペースを指定数追加する(Space)1,String関数の使用方法構文String(Number,Character)説明Number:文字をいくつ並べるのかを整数値で指定します。Character:文字の文字コード、または文字列を指定します。この文字が引数Nu......
  • SciTech-Math-AdvancedAlgebra-Linear Spaces(Vector Spaces) and Subspace: The Colu
    https://math.mit.edu/~gs/dela/dela_5-1.pdfhttps://people.math.harvard.edu/~knill/teaching/math22b2019/handouts/lecture01.pdfhttps://web.stanford.edu/group/dabmgroup/cgi-bin/dabm/wp-content/uploads/2021/12/Lecture_14.pdfN-elementorderedNumberSequence......